リーフがソートするデータのソースなど、データフローの要件については何も述べていません。分業の観点から、リーフ ノードはソートされますが、ブランチはマージするだけで済みます。ある意味では、スタックの代わりにプロセスと FIFO を使用するハイブリッド マージソートを作成しています。
前述のように、並べ替える値の配列を割り当て、すべての FIFO をメイン プロセスの前に作成するという、シンプルだが洗練されていないアプローチを使用できます。各子の識別子またはインデックス番号に基づいて、配列全体と適切な FIFO (たとえば、ノードNが親にデータを送信するために使用する FIFO) からデータの範囲を選択します。たとえば、 で作成された子プロセスは親のアドレス空間を共有し、グローバル スコープで配列を参照できることを思い出してください。fifo.N
fork
二分木はうまく配列に詰め込まれます。ウィキペディアの二分木によると
二分木は、配列内の暗黙的なデータ構造として幅優先の順序で格納することもできます。木が完全な二分木である場合、この方法はスペースを無駄にしません。このコンパクトな配置では、ノードにインデックスiがある場合、その子はインデックス2i+1 (左の子の場合) と2i+2 (右の子の場合) で見つかり、親 (存在する場合) はインデックス ⌊ で見つかります。 <em>(i-1)/2⌋ (ルートのインデックスが 0 であると仮定)。
⌊<em>x⌋ は x を超えない最大の整数であり、xの下限とも呼ばれます。C では、 の値を 型の変数に代入することでフロアを取得できます。(i-1)/2
int
ツリーの周りにノード識別子をスレッド化するには、次のようなコードを使用できます。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
void proc_tree(int i, int current_depth, int max_depth)
{
pid_t kid = fork();
if (kid == -1) {
fprintf(stderr, "[%d]: fork: %s\n", getpid(), strerror(errno));
}
else if (kid == 0) {
/* child */
printf("[%d]: i=%d (depth %d)\n", getpid(), i, current_depth);
if (current_depth < max_depth) {
proc_tree(2*i+1, current_depth+1, max_depth);
proc_tree(2*i+2, current_depth+1, max_depth);
}
exit(EXIT_SUCCESS);
}
else {
/* parent */
pid_t pid;
int status;
pid = waitpid(kid, &status, 0);
if (pid == -1)
fprintf(stderr, "[%z]: waitpid: %s\n", getpid(), strerror(errno));
}
}
で呼び出します
int main(int argc, char *argv[])
{
int depth;
if (argc != 2) {
fprintf(stderr, "Usage: %s depth\n", argv[0]);
return EXIT_FAILURE;
}
depth = atoi(argv[1]);
if (depth < 0) {
fprintf(stderr, "%s: depth must be non-negative\n", argv[0]);
return EXIT_FAILURE;
}
proc_tree(0, 0, depth);
return EXIT_SUCCESS;
}
出力例:
$ ./ツリーソート 3
[28837]: i=0 (深さ0)
[28838]: i=1 (深さ1)
[28839]: i=3 (深さ2)
[28840]: i=7 (深さ3)
[28841]: i=8 (深さ3)
[28842]: i=4 (深さ2)
[28843]: i=9 (深さ3)
[28844]: i=10 (深さ3)
[28845]: i=2 (深さ1)
[28846]: i=5 (深さ2)
[28847]: i=11 (深さ3)
[28848]: i=12 (深さ3)
[28849]: i=6 (深さ2)
[28850]: i=13 (深さ3)
[28851]: i=14 (深さ3)