ツリー/グラフをトラバースするとき、幅優先と深さ優先の違いは何ですか?コーディングや疑似コードの例はすばらしいでしょう。
ツリー/グラフをトラバースするとき、幅優先と深さ優先の違いは何ですか?コーディングや疑似コードの例はすばらしいでしょう。
回答:
これらの2つの用語は、木を歩く2つの異なる方法を区別します。
違いを示すだけでおそらく最も簡単です。ツリーについて考えてみましょう。
A
/ \
B C
/ / \
D E F
深さ優先走査の順にノードを訪問します
A, B, D, C, E, F
次のステップに進む前に、片方の脚をずっと下がっていることに注意してください。
広最初のトラバーサルがこの順にノードを訪問します
A, B, C, D, E, F
ここでは、下に行く前に、各レベル全体で作業します。
(トラバーサル順序にはあいまいさがいくつかあることに注意してください。ツリーの各レベルで「読み取り」順序を維持するためにだましました。どちらの場合でも、Cの前または後にBに到達でき、同様にFの前または後のE。これは重要な場合と重要でない場合があり、アプリケーションによって異なります...)
どちらの種類のトラバーサルも、疑似コードで実現できます。
Store the root node in Container
While (there are nodes in Container)
N = Get the "next" node from Container
Store all the children of N in Container
Do some work on N
2つのトラバーサル順序の違いは、の選択にありContainer
ます。
再帰的な実装は次のようになります
ProcessNode(Node)
Work on the payload Node
Foreach child of Node
ProcessNode(child)
/* Alternate time to work on the payload Node (see below) */
再帰は、子のないノードに到達したときに終了するため、有限の非循環グラフで終了することが保証されています。
この時点で、私はまだ少しごまかしています。少し利口であなたもできる仕事上のノードを順に:
D, B, E, F, C, A
これは深さ優先のバリエーションであり、ツリーを上に戻るまで各ノードで作業を行いません。ただし、途中で上位のノードを訪問して、子供を見つけました。
このトラバーサルは再帰的な実装ではかなり自然であり(最初の "Work"行の代わりに上記の "Alternate time"行を使用)、明示的なスタックを使用する場合はそれほど難しくありませんが、練習として残しておきます。
A, B, D, C, E, F
-最初に表示されたもの)、接頭辞(- D, B, A, E, C, F
ソートに使用:AVLツリーとして追加してから、接尾辞を読み取る)、または後置(D, B, E, F, C, A
表示された代替)トラバーサルを取得できることに注意してください。名前は、ルートを処理する位置によって与えられます。infixはバイナリツリーに対してのみ意味があることに注意してください。@batbratそれらは名前です...あなたが尋ねてからの時間を考えると、おそらくすでに知っています。
この写真は、幅と深さという言葉が使用されているコンテキストについての考えを与えるはずです。
深さ優先の検索アルゴリズムは、開始点からできるだけ早く離れたい場合と同じように機能します。
それは一般的にStack
行き止まりに到達したときにどこに行くべきかを覚えておくためにを使用します。
従うべきルール:最初の頂点Aを Stack
Javaコード:
public void searchDepthFirst() {
// Begin at vertex 0 (A)
vertexList[0].wasVisited = true;
displayVertex(0);
stack.push(0);
while (!stack.isEmpty()) {
int adjacentVertex = getAdjacentUnvisitedVertex(stack.peek());
// If no such vertex
if (adjacentVertex == -1) {
stack.pop();
} else {
vertexList[adjacentVertex].wasVisited = true;
// Do something
stack.push(adjacentVertex);
}
}
// Stack is empty, so we're done, reset flags
for (int j = 0; j < nVerts; j++)
vertexList[j].wasVisited = false;
}
アプリケーション:深さ優先検索は、ゲームのシミュレーション(および現実世界のゲームのような状況)でよく使用されます。典型的なゲームでは、いくつかの可能なアクションの1つを選択できます。それぞれの選択肢はさらなる選択肢につながり、それぞれの選択肢はさらなる選択肢につながります。
Queue
ます。Javaコード:
public void searchBreadthFirst() {
vertexList[0].wasVisited = true;
displayVertex(0);
queue.insert(0);
int v2;
while (!queue.isEmpty()) {
int v1 = queue.remove();
// Until it has no unvisited neighbors, get one
while ((v2 = getAdjUnvisitedVertex(v1)) != -1) {
vertexList[v2].wasVisited = true;
// Do something
queue.insert(v2);
}
}
// Queue is empty, so we're done, reset flags
for (int j = 0; j < nVerts; j++)
vertexList[j].wasVisited = false;
}
アプリケーション:幅優先検索では、最初に始点から1エッジ離れているすべての頂点が検出され、次に2エッジ離れているすべての頂点が検出されます。これは、開始頂点から特定の頂点までの最短パスを見つけようとしている場合に役立ちます。
うまくいけば、幅優先検索と深さ優先検索を理解するのに十分なはずです。詳細については、Robert Laforeによる優れたデータ構造の本のグラフの章をお勧めします。
この二分木を考えると:
幅優先トラバーサル:
各レベルを左から右にトラバースします。
「私はGです。私の子供はDです。私、私の孫はB、E、H、Kです。彼らの孫はA、C、Fです。」
- Level 1: G
- Level 2: D, I
- Level 3: B, E, H, K
- Level 4: A, C, F
Order Searched: G, D, I, B, E, H, K, A, C, F
深さ優先トラバーサル:
レベル全体で一度にトラバーサルを行うことはできません。代わりに、トラバーサルは最初にツリーの(ルートからリーフへの)デプスに飛び込みます。ただし、単純に上下するよりも少し複雑です。
3つの方法があります。
1) PREORDER: ROOT, LEFT, RIGHT.
You need to think of this as a recursive process:
Grab the Root. (G)
Then Check the Left. (It's a tree)
Grab the Root of the Left. (D)
Then Check the Left of D. (It's a tree)
Grab the Root of the Left (B)
Then Check the Left of B. (A)
Check the Right of B. (C, and it's a leaf node. Finish B tree. Continue D tree)
Check the Right of D. (It's a tree)
Grab the Root. (E)
Check the Left of E. (Nothing)
Check the Right of E. (F, Finish D Tree. Move back to G Tree)
Check the Right of G. (It's a tree)
Grab the Root of I Tree. (I)
Check the Left. (H, it's a leaf.)
Check the Right. (K, it's a leaf. Finish G tree)
DONE: G, D, B, A, C, E, F, I, H, K
2) INORDER: LEFT, ROOT, RIGHT
Where the root is "in" or between the left and right child node.
Check the Left of the G Tree. (It's a D Tree)
Check the Left of the D Tree. (It's a B Tree)
Check the Left of the B Tree. (A)
Check the Root of the B Tree (B)
Check the Right of the B Tree (C, finished B Tree!)
Check the Right of the D Tree (It's a E Tree)
Check the Left of the E Tree. (Nothing)
Check the Right of the E Tree. (F, it's a leaf. Finish E Tree. Finish D Tree)...
Onwards until...
DONE: A, B, C, D, E, F, G, H, I, K
3) POSTORDER:
LEFT, RIGHT, ROOT
DONE: A, C, B, F, E, D, H, K, I, G
使用法(別名、なぜ気にするのか):
深さ優先トラバーサルメソッドの簡単なQuoraの説明と、それらが一般的にどのように使用されるかを本当に楽しんだ
。 「
「プレオーダートラバーサルは、[バイナリ検索ツリー]のコピーを作成するために使用されます。」
「ポストオーダートラバーサルは、[バイナリ検索ツリー]を削除するために使用されます。」
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing
両方のコードをいくつかのコード行を切り替えるだけでどちらかのアルゴリズムが得られるように両方を書くのは興味深いと思います。そうすれば、最初のように思えるほどディレマが強くないことがわかります。 。
私は個人的に、BFSを景観の洪水として解釈するのが好きです。低高度の地域が最初に洪水になり、その後にのみ高高度の地域が続きます。地理の本に見られるように、地形の標高を等高線と考えると、物理学の場合と同じように、BFSが同じ等高線の下のすべての領域を同時に満たすことが簡単にわかります。したがって、高度を距離またはスケーリングされたコストとして解釈すると、アルゴリズムをかなり直感的に理解できます。
これを念頭に置いて、幅優先検索の背後にある考え方を簡単に適用して、最小全域木を簡単に、最短経路で、そして他の多くの最小化アルゴリズムを見つけることができます。
私はまだDFSの直感的な解釈は見ていません(迷路に関する標準的な解釈のみですが、BFSやフラッディングほど強力ではありません)ので、私にとっては、BFSは上記の物理現象とよりよく相関しているようです。 DFSは、合理的なシステム(つまり、チェスゲームや迷路から抜け出すためにどちらの動きをするかを決定する人やコンピューター)の選択肢のディレマとよりよく相関しています。
したがって、私にとって両者の違いは、どの自然現象が実際の伝搬モデル(トランスバーシング)に最もよく一致するかによって異なります。