再帰なしで2分探索木を渡り歩こう!
どもども。
どうやるのかなぁと思ったので,調べたりして勉強しました。
最初はスタックでも使って記録していくのかなぁと思ったけど,
スタック不要な方法があった。
フラグを使うのもあったけど,2回以上渡り歩く際には,
フラグのリセットが必要になる予感。
ちなみに,これは,ワタシが考えたわけではないです。もちのろんですよ。
サンプルコード
#include <stdio.h> #include <assert.h> typedef struct tree { struct tree *parent; /* これ重要 */ struct tree *left; struct tree *right; int data; } Tree; /* * 再帰なしで,2分探索木を渡り歩こう。 */ static void traverse(Tree *root, void f(Tree *node)) { if (!root) { printf("なるぽ。"); return; } Tree *prev = root->parent; /* 1つ前に見た節へのポインタ */ Tree *curr = root; /* 現在見ようとしている節へのポインタ */ while (curr) { if (prev == curr->parent) { /* curr にやってきました。 */ //f(curr); // preorder なら,ここで関数を呼ぶ。 /* まず左をみます。 */ if (curr->left) { prev = curr; curr = curr->left; continue; } else { /* 左部分木がない場合は,左をみたことにする。 */ prev = curr->left; } } if (prev == curr->left) { /* もう左側には行ってきました。*/ f(curr); // inorder の場合はここで関数を適用。 /* 左部分木を見たので,右部分木をチェックする。 */ if (curr->right) { /* 右部分木がある場合は,そっちへ行ってチェックする。 */ prev = curr; curr = curr->right; continue; } else { /* 右にはもうなにもない。。。 */ prev = curr->right; } } if (prev == curr->right) { // f(curr); // postorder ならここで。 /* 左右の部分木へ行ってきたので,1つ上へ上る。 */ prev = curr; curr = curr->parent; } } return; } static void print(Tree *p) { assert(p != NULL); printf("%d, ", p->data); } int main(void) { // こんな感じの木。 // 10 // 5 15 // 2 13 18 Tree root = { NULL, NULL, NULL, 10 }; Tree left = { &root, NULL, NULL, 5 }; Tree right = { &root, NULL, NULL, 15 }; Tree lleft = { &left, NULL, NULL, 2 }; Tree rleft = { &right, NULL, NULL, 13 }; Tree rright = { &right, NULL, NULL, 18 }; root.left = &left; root.right = &right; left.left = &lleft; right.left = &rleft; right.right = &rright; traverse(&root, print); printf("\n"); return 0; }
実行結果
% gcc -Wall -W -g bsearchtree.c -o bsearchtree % ./bsearchtree 2, 5, 10, 13, 15, 18,
たぶんこれでオッケー牧場。