【二分木ソートアルゴリズムのデータ構造】

二分木は非常に重要なツリー構造であり、そのストレージ構造と操作は比較的単純であり、ツリーは二分木に変換するのも簡単です。この記事では主に、3種類のトラバーサルに分けられるバイナリツリーのトラバーサルについて説明します。 :プレオーダー、ミドルオーダー、ポストオーダー方法では、再帰を使用してコードの導入をトラバースするのは簡単です。以下では、最初に、再帰的なプレオーダートラバーサルと非再帰的なミドルオーダーおよびポストオーダートラバーサルを紹介します。

二分木探索の定義

  1. 最初にトラバースします。
    二分木が空の場合は操作を行いません。それ以外の場合は、次の操作を順番に実行します。
  • ルートノードにアクセスします
  • 最初にルートノードの左側のサブツリーをトラバースします
  • 最初にルートノードの右側のサブツリーをトラバースします
  1. インオーダートラバーサル
    バイナリツリーが空の場合、操作はありません。それ以外の場合は、次の操作を順番に実行します。
  • ルートノードの左側のサブツリーを中間の順序でトラバースします
  • ルートノードにアクセスします
  • ルートノードの右側のサブツリーを中間の順序でトラバースします
  1. ポストオーダートラバーサル
    バイナリツリーが空の場合、操作はありません。それ以外の場合は、次の操作を順番に実行します。
  • ポストオーダーは、ルートノードの左側のサブツリーをトラバースします
  • ポストオーダーは、ルートノードの右側のサブツリーをトラバースします
  • ルートノードにアクセスします

二分木の例の図
は、この記事で定義されているタイプと一致しません。

二分木のタイプの説明

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. 積み重ねた後、左側を確認してください。スタックを解除した後、右側を確認してください。
  2. 非再帰的なインオーダートラバーサルの特徴は、高度なスタックルートノードであり、左側のノードがあるかどうかが判断されます。
  3. スタックをプッシュし続ける場合、空の場合はスタックをポップし、スタックをポップした後、正しいノードがあるかどうかを判断します
  4. スタックに適切なノードがある場合。等々。スタックにプッシュするアクションは継続的であり(左側のノードがある限り、スタックにプッシュされ続けます)、
    ポップのアクションは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に設定します。ルートノードが空でない場合は、スタックにプッシュしてノードの訪問数をゼロに設定し、左側の要素があるかどうかを再度判断し、ある場合は続行します。スタックをプッシュします。(左の要素は空の端です)
  2. 終了後、スタックをポップし、スタックが空であるかどうかを判断し、空でない場合はスタックの最上位要素を取り出します。適切な子供がいるかどうか、または訪問数がゼロかどうかを判断します。
  3. 適切な子がなく、訪問数が1の場合、スタックがポップされます。それ以外の場合(つまり、適切な子があり、訪問数がゼロの場合)、ノードの訪問数を1に設定します。次に、適切な子のアドレスをノードに割り当てます。
  4. ノードが空かどうかを判別します。空でない場合は、スタックをプッシュして、ノードの訪問数をゼロに設定します。左側の要素にアクセスします。順番に循環する(結合されたコード)
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

おすすめ

転載: blog.csdn.net/qq_37640410/article/details/108196564