私は最近、BSTを十分に活用している一方で、インオーダートラバーサル以外を使用することさえ考えたことがないことに気付きました(プログラムを前後のトラバーサルに使用するのがいかに簡単であるかを知っており、知っています)。
これに気づいたとき、私は私の古いデータ構造の教科書の一部を引き出して、予約注文と注文注文の走査の有用性の背後にある理由を探しました-彼らは多くのことを言いませんでした。
プレオーダー/ポストオーダーを実際に使用する場合の例は何ですか?順序より意味があるのはいつですか?
私は最近、BSTを十分に活用している一方で、インオーダートラバーサル以外を使用することさえ考えたことがないことに気付きました(プログラムを前後のトラバーサルに使用するのがいかに簡単であるかを知っており、知っています)。
これに気づいたとき、私は私の古いデータ構造の教科書の一部を引き出して、予約注文と注文注文の走査の有用性の背後にある理由を探しました-彼らは多くのことを言いませんでした。
プレオーダー/ポストオーダーを実際に使用する場合の例は何ですか?順序より意味があるのはいつですか?
回答:
バイナリツリーで事前順序、順序順、事後順序をどのような状況で使用するかを理解する前に、各走査戦略がどのように機能するかを正確に理解する必要があります。例として次のツリーを使用します。
ツリーのルートは7、左端のノードは0、右端のノードは10です。
予約注文トラバーサル:
概要:ルート(7)で始まり、右端のノード(10)
走査シーケンス:7、1、0、3、2、5、4、6、9、8、10
順序トラバーサル:
概要:左端のノード(0)で始まり、右端のノード(10)で終わります
走査シーケンス:0、1、2、3、4、5、6、7、8、9、10
注文後のトラバーサル:
概要:左端のノード(0)で始まり、ルート(7)で終わります
走査シーケンス:0、2、4、6、5、3、1、8、10、9、7
プログラマーが選択する走査戦略は、設計されているアルゴリズムの特定のニーズによって異なります。目標は速度です。そのため、必要なノードを最速で実現する戦略を選択してください。
葉を検査する前に根を探索する必要があることがわかっている場合は、すべての葉の前にすべての根に出会うため、事前注文を選択します。
ノードの前にすべての葉を探索する必要があることがわかっている場合は、葉の検索でルートを検査する時間を無駄にしないため、ポストオーダーを選択します。
ツリーがノードに固有のシーケンスを持っていることがわかっていて、ツリーを元のシーケンスに平坦化したい場合は、順序トラバーサルを使用する必要があります。ツリーは、作成されたのと同じ方法で平坦化されます。事前注文または事後注文のトラバーサルでは、ツリーの作成に使用されたシーケンスにツリーを巻き戻さない場合があります。
struct Node{
int data;
Node *left, *right;
};
void preOrderPrint(Node *root)
{
print(root->name); //record root
if (root->left != NULL) preOrderPrint(root->left); //traverse left if exists
if (root->right != NULL) preOrderPrint(root->right);//traverse right if exists
}
void inOrderPrint(Node *root)
{
if (root.left != NULL) inOrderPrint(root->left); //traverse left if exists
print(root->name); //record root
if (root.right != NULL) inOrderPrint(root->right); //traverse right if exists
}
void postOrderPrint(Node *root)
{
if (root->left != NULL) postOrderPrint(root->left); //traverse left if exists
if (root->right != NULL) postOrderPrint(root->right);//traverse right if exists
print(root->name); //record root
}
予約購入:木のコピーを作成するために使用されます。たとえば、ツリーのレプリカを作成する場合は、ノードを配列に配置し、前順走査を行います。次に、配列の各値に対して新しいツリーで挿入操作を実行します。元のツリーのコピーが作成されます。
In-order:: BSTでノードの値を降順に取得するために使用されます。
ポストオーダー::リーフからルートへのツリーの削除に使用されます
単純にツリーの階層形式を線形形式で出力したい場合は、おそらくプレオーダートラバーサルを使用します。例えば:
- ROOT
- A
- B
- C
- D
- E
- F
- G
TreeView
、GUIアプリケーションのコンポーネント内。
プレオーダーとポストオーダーは、それぞれトップダウンとボトムアップの再帰アルゴリズムに関連しています。与えられた再帰的アルゴリズムをバイナリツリーで反復的に記述したい場合、これは基本的に行うことです。
さらに、前後順のシーケンスが一緒に手元のツリーを完全に指定し、コンパクトなエンコーディング(少なくともスパースツリーの場合)が生成されることを確認します。
この違いが本当の役割を果たすのを目にする場所はたくさんあります。
私が指摘する素晴らしいものの1つは、コンパイラーのコード生成です。次のステートメントについて考えてみます。
x := y + 32
そのためのコードを生成する方法は、(当然ながら)最初にyをレジスターにロードするコードを生成し、32をレジスターにロードしてから、2つを追加する命令を生成することです。それを操作する前に何かがレジスターになければならないので(仮定しましょう。常に定数のオペランドを実行できますが、何でも)、この方法で実行する必要があります。
一般に、この質問に対する答えは基本的にこれに削減されます。データ構造の異なる部分の処理間に依存関係がある場合、違いは本当に重要です。これは、要素を印刷するとき、コードを生成するとき(外部状態によって違い、もちろんこれをモナドで表示することもできます)、または最初に処理される子に応じて計算を伴う構造に対して他のタイプの計算を行うときに表示されます。