バイナリ検索ツリーに関するわかりやすい記事(私を突いてください)では、バイナリ検索ツリーの性質が主に紹介されています。この記事では、バイナリツリーのトラバーサルについて引き続き紹介します。
バイナリ検索ツリーのトラバース
ツリーのすべてのノードをトラバースすることは、一度だけ訪問することです。ルートノードの位置に応じて、主にプレオーダートラバーサル、ミドルオーダートラバーサル、ポストオーダートラバーサルに分けられます。バイナリ検索ツリーと通常のバイナリツリーのトラバースはまったく同じであるため、以下では、バイナリ検索ツリーであるかバイナリツリーであるかを区別しないことに注意してください。
事前注文トラバーサル
バイナリツリーのプレオーダートラバーサル操作は次のとおりです。
- ルートノードにアクセスします
- プレオーダーは左側のサブツリーをトラバースします
- プレオーダーは右側のサブツリーをトラバースします
たとえば、次の図では、バイナリツリーのプレオーダートラバーサルノードアクセス順序は3 1 2 5 4 6です。
上記で分析したプレオーダートラバーサルの操作手順によると、再帰的な方法でバイナリツリーのプレオーダーアクセスを簡単に実装できることを確認するのは難しくありません。
//前序遍历递归版本
void preOrder(struct node *root)
{
if(root != NULL)
{
cout << root->data << " ";
preOrder(root->left);
preOrder(root->right);
}
}
実際、バイナリツリーのプレオーダートラバーサルは、非再帰的な方法で実装することもできます。ルートノードに対応する右側のサブツリーをトラバースするには、ルートノードをトラバースした後にルートノードを取得する必要があるため、スタックを使用して訪問者を格納することを検討できます。コード実装のルートノードは次のとおりです。
//前序遍历的非递归版本
void preOrder(struct node *root)
{
stack<struct node *> s;
while (root != NULL || !s.empty())
{
if (root != NULL)
{
//访问结点并入栈
cout << root->data << " ";
s.push(root);
root = root->left; //访问左子树
}
else
{
root = s.top(); //回溯至父亲结点
s.pop();
root = root->right; //访问右子树
}
}
cout << endl;
}
順序どおりのトラバーサル
バイナリツリーの中次トラバーサル操作は次のとおりです。
- 左サブツリーの中次トラバーサル
- ルートノードにアクセスします
- 右サブツリーの順序どおりのトラバース
たとえば、次の図では、バイナリツリートラバーサル内のノードのアクセス順序は1 2 3 4 56です。
事前注文トラバーサルと同様に、再帰的または非再帰的な方法で実装することもでき、アクセスの順序が異なることを除いて、考え方は似ています。2つの実装は次のとおりです。
//中序遍历递归版本
void inOrder(struct node *root)
{
if(root != NULL)
{
inOrder(root->left);
//和前序遍历相比,只是输出语句换了个位置唯一
cout << root->data << " ";
inOrder(root->right);
}
}
//中序遍历的非递归版本
void inOrder(struct node *root)
{
stack<struct node *> s;
while (root != NULL || !s.empty())
{
if (root != NULL)
{
s.push(root);
root = root->left;
}
else
{
//访问完左子树后才访问根结点
root = s.top();
cout << root->data << " ";
s.pop();
root = root->right; //访问右子树
}
}
cout << endl;
}
その後のトラバーサル
バイナリツリーのポストオーダートラバーサル操作は次のとおりです。
- 左側のサブツリーの注文後のトラバーサル
- 右のサブツリーの注文後のトラバーサル
- ルートノードにアクセスします
たとえば、次の図では、バイナリツリーのポストオーダートラバーサルノードアクセス順序は2 1 4 6 5 3です。
バイナリツリーのポストオーダートラバーサルの再帰バージョンは、次のようにプレオーダーミドルオーダーに似ています。
//后序遍历递归版本
void postOrder(struct node *root)
{
if(root != NULL)
{
postOrder(root->left);
postOrder(root->right);
//最后访问根节点
cout << root->data << " ";
}
}
ポストオーダートラバーサルの非再帰的アルゴリズムはより複雑で、1つのスタックで実装できますが、プロセスは非常に面倒です。2つのスタックを使用して、ポストオーダートラバーサルの非再帰的アルゴリズムを実装することを検討できます。ポストオーダートラバーサルは、最初に特定のノードをトラバースし、次にその右の子をトラバースし、次にその左の子をトラバースするという、次のトラバースの逆のプロセスと見なすことができることに注意してください。このプロセスの逆は、注文後のトラバーサルです。アルゴリズムの手順は次のとおりです。
(1)ルートノードを最初のスタックにプッシュします。
(2)スタックからノードをポップし、スタック出力にプッシュします。
(3)次に、ノードの左の子と右の子を最初のスタックにプッシュします。
(4)スタックが空になるまで手順2と3を繰り返します。
(5)これで、すべてのノードがスタック出力にプッシュされ、ポストオーダートラバーサルの順序で格納され、バイナリツリーのポストオーダートラバーサルの結果として直接ポップアウトされます。
コードは次のように実装されています。
//后序遍历的非递归版本
void postOrder(struct node *root)
{
if (!root) return;
stack<struct node*> s, output;
s.push(root);
while (!s.empty())
{
struct node *curr = s.top();
output.push(curr);
s.pop();
if (curr->left)
s.push(curr->left);
if (curr->right)
s.push(curr->right);
}
while (!output.empty())
{
cout << output.top()->data << " ";
output.pop();
}
cout << endl;
}
推奨読書:
【福祉】自分で集めたオンラインブティックコースの動画共有(
パート1 )【システム設計】LRUキャッシュ
【データ構造とアルゴリズム】リンクリストがわかりやすい
【データ構造とアルゴリズム】ビットソーティングがわかりやすい
【C ++注意事項】C ++ 11コンカレントプログラミング(1)スレッドジャーニーの開始
[C ++ノート] C / C ++ポインターの使用における一般的な落とし穴
[C ++ノート]静的および動的ライブラリの詳細な説明(上)
サーバーのバックグラウンドテクノロジースタックの知識の概要の共有に焦点を当てる
コミュニケーションと共通の進歩に注意を払うことを歓迎します
コーディング
コードファーマーには、テクノロジーを簡単にするためのわかりやすい技術記事を提供する正しい方法があります。