二分木は非常に重要なツリー構造であり、そのストレージ構造と操作は比較的単純であり、ツリーは二分木に変換するのも簡単です。この記事では主に、3種類のトラバーサルに分けられるバイナリツリーのトラバーサルについて説明します。 :プレオーダー、ミドルオーダー、ポストオーダー方法では、再帰を使用してコードの導入をトラバースするのは簡単です。以下では、最初に、再帰的なプレオーダートラバーサルと非再帰的なミドルオーダーおよびポストオーダートラバーサルを紹介します。
二分木探索の定義
- 最初にトラバースします。
二分木が空の場合は操作を行いません。それ以外の場合は、次の操作を順番に実行します。
- ルートノードにアクセスします
- 最初にルートノードの左側のサブツリーをトラバースします
- 最初にルートノードの右側のサブツリーをトラバースします
- インオーダートラバーサル
バイナリツリーが空の場合、操作はありません。それ以外の場合は、次の操作を順番に実行します。
- ルートノードの左側のサブツリーを中間の順序でトラバースします
- ルートノードにアクセスします
- ルートノードの右側のサブツリーを中間の順序でトラバースします
- ポストオーダートラバーサル
バイナリツリーが空の場合、操作はありません。それ以外の場合は、次の操作を順番に実行します。
- ポストオーダーは、ルートノードの左側のサブツリーをトラバースします
- ポストオーダーは、ルートノードの右側のサブツリーをトラバースします
- ルートノードにアクセスします
二分木の例の図
は、この記事で定義されているタイプと一致しません。
二分木のタイプの説明
typedef struct BTNode
{
int elem;
struct BTNode *left,*right;
}*BinTree;
【プレオーダートラバーサル】
void PreOrder(BinTree root)
{
if(root!=NULL)
{
printf("%4d",root->elem); /*访问根结点*/
PreOrder(root->left); /*先序遍历根结点的左子树*/
PreOrder(root->right); /*先序遍历根结点的右子树*/
}
}
インオーダートラバーサルとそれに続く再帰トラバーサル
ここではあまり紹介せずに、非再帰トラバーサルから始めましょう。
[非再帰的インオーダートラバーサル]
バイナリツリーインオーダートラバーサルの非再帰的アルゴリズムの主なアイデアは、変数rootをルートノードへのポインターにして、ルートノードからトラバースすることです。明らかに、ルートノードは最初に検出されたときにはアクセスされませんが、スタックにプッシュされます。これは、現時点では、ルートが指すルートノードとその右側のサブツリーがまだアクセスされていないため、ルートをに保存する必要があるためです。スタックして、左側のサブツリーの後でアクセスできるようにします。スタックからルートを取得し、ルートノードとその右側のサブツリーにアクセスします。ルートがスタックに入った後、ルートは中央の順序で左側のサブツリーをトラバースします。つまり、ルートの左側の子をルートに割り当て、左側のチェーンが空になり、左側のサブツリーがトラバースされてノードが終了するまで、左側のチェーンをウォークダウンします。 。スタック要素をルートに割り当てます。ノードに遭遇するのはこれが2回目です。この時点で、左側のサブツリーにアクセスしています。中次トラバーサルの定義に従って、ルートノードにアクセスします(の情報を出力します。 node)、次にミドルオーダーその右のサブツリーをトラバースします。つまり、rootの右の子をrootに割り当て、rootが空のスタックになるまで上記のプロセスを繰り返します。
大まかに次のように要約されます。
- 積み重ねた後、左側を確認してください。スタックを解除した後、右側を確認してください。
- 非再帰的なインオーダートラバーサルの特徴は、高度なスタックルートノードであり、左側のノードがあるかどうかが判断されます。
- スタックをプッシュし続ける場合、空の場合はスタックをポップし、スタックをポップした後、正しいノードがあるかどうかを判断します
- スタックに適切なノードがある場合。等々。スタックにプッシュするアクションは継続的であり(左側のノードがある限り、スタックにプッシュされ続けます)、
ポップのアクションは1回だけです。スタックをポップした後、正しいノードがあるかどうかが判断されるため、ノードが空でなくても、ポップが続く場合は上記のプロセスが繰り返されます。
スタックを定義する
#define MaxSize
typedef struct
{
BinTree elem[MaxSize];
int top;
}SeqStack;
中次走査の非再帰的実現のアルゴリズム記述:
void InOrder(BinTree root)
{
SeqStack s;
s.top=-1;
do
{
while(root!=NULL)
{
s.top++;
if(s.top>=MaxSize-1)
{
printf("栈已经满了!\n");
return ;
}
else
{
s.elem[s.top]=root;
root=root->left;
}
}
if(s.top!=-1)
{
root=s.elem[s.top];
s.top--;
printf("\n%4d",root->elem);
root=root->right;
}
}while((s.top!=-1)||(root!=NULL));
}
[非再帰的な後続のトラバーサル]
- スタックの最上位を-1に設定します。ルートノードが空でない場合は、スタックにプッシュしてノードの訪問数をゼロに設定し、左側の要素があるかどうかを再度判断し、ある場合は続行します。スタックをプッシュします。(左の要素は空の端です)
- 終了後、スタックをポップし、スタックが空であるかどうかを判断し、空でない場合はスタックの最上位要素を取り出します。適切な子供がいるかどうか、または訪問数がゼロかどうかを判断します。
- 適切な子がなく、訪問数が1の場合、スタックがポップされます。それ以外の場合(つまり、適切な子があり、訪問数がゼロの場合)、ノードの訪問数を1に設定します。次に、適切な子のアドレスをノードに割り当てます。
- ノードが空かどうかを判別します。空でない場合は、スタックをプッシュして、ノードの訪問数をゼロに設定します。左側の要素にアクセスします。順番に循環する(結合されたコード)
void PostOrder(BinTree root)
{
SeqStack s;
s.top=-1;
while(root!=NULL)
{
s.top++;
if(s.top==MaxSize-1)
{
printf("栈已经满了!\n");
printf("Error");
}
else
{
root->count=0;
s.elem[s.top]=root;
root=root->left;
}
}
while(s.top!=-1)
{
root=s.elem[s.top];
if(root->right==NULL||root->count==1)
{
printf("\n%c",root->elem);
s.top--;
}
else if(root->right!=NULL&&root->count!=1)
{
root->count=1;
root=root->right;
while(root!=NULL)
{
s.top++;
s.elem[s.top]=root;
root->count=0;
root=root->left;
}
}
}
}
プレオーダートラバーサル:ABDECF
ミドルオーダートラバーサル:DBEAFC
ポストオーダートラバーサル:DEBFCA