Answers:
这两个术语区分了步行树的两种不同方式。
展示差异可能是最容易的。考虑这棵树:
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
两种遍历顺序之间的差异在于对的选择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
这是深度优先的一种变体,在这种情况下,直到我向后走到树上之前,我不会在每个节点上进行工作。但是,我在去的途中参观了较高的节点,以找到他们的孩子。
这种遍历在递归实现中是很自然的(使用上面的“ Alternate time”行而不是第一条“ Work”行),并且如果您使用显式堆栈也不会太难,但是我将其保留为练习。
A, B, D, C, E, F
-提出的第一个),中缀(D, B, A, E, C, F
-用于排序:添加为AVL树然后读取中缀)或后缀(D, B, E, F, C, A
提出的替代方法)遍历。名称由您处理根的位置给出。应该注意的是,对于二叉树,infix仅有意义。@batbrat就是这些名字...自从您问了这个时间以来,您可能已经知道了。
这张图片应该使您对使用“ 广度”和“ 深度 ”一词的上下文有一个了解。
深度优先搜索算法的作用就好像它希望尽快远离起点。
它通常使用a 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;
}
应用程序:深度优先搜索通常用于模拟游戏(以及现实世界中类似游戏的情况)。在典型的游戏中,您可以选择几种可能的动作之一。每个选择都会导致进一步的选择,每个选择都会导致进一步的选择,依此类推成为不断扩大的可能性树形图。
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;
}
应用程序:广度优先搜索首先查找距起点一个边缘的所有顶点,然后查找相距两个边缘的所有顶点,依此类推。如果您要查找从起始顶点到给定顶点的最短路径,这将很有用。
希望这足以理解广度优先和深度优先搜索。为了进一步阅读,我会推荐Robert Lafore撰写的出色数据结构书中的Graphs一章。
给定这个二叉树:
广度优先遍历:
从左到右遍历每个级别。
“我是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
深度优先遍历:一次
不能遍历整个级别。相反,遍历首先进入树的深度(从根到叶)。但是,这不仅仅是简单地上下。
有三种方法:
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解释以及它们的常用方式:
“按顺序遍历将打印值(以BST(二进制搜索树)的顺序) “
”预遍历用于创建[二进制搜索树]的副本。
“后遍历用于删除[二进制搜索树]。”
https://www.quora.com/What-is-the-the-use-of-pre-order-and-post-order-traversal-binary-trees-in-computing
我认为以两种方式编写它们都是很有趣的:仅通过切换几行代码就可以为您提供一种算法或另一种算法,这样您便会发现您的视差并不像刚开始时那么强。
我个人喜欢将BFS解释为淹没景观:低海拔地区将首先被淹没,然后高海拔地区才会被淹没。如果您将地形海拔高度想象成等高线,就像我们在地理书籍中看到的那样,那么很容易看到BFS同时填充了同一等高线下的所有区域,就像物理学中那样。因此,将海拔高度解释为距离或按比例换算的成本可以很好地直观了解该算法。
考虑到这一点,您可以轻松地根据广度优先搜索的思想来轻松找到最小生成树,最短路径以及许多其他最小化算法。
我还没有看到对DFS的任何直观解释(仅是关于迷宫的标准解释,但它不如BFS 1和洪水泛滥那么强大),所以对我来说,BFS似乎与上述物理现象更好地关联,而DFS与理性系统上的选择困境有更好的关联(例如,人或计算机决定在国际象棋游戏中走出困境或走出迷宫)。
因此,对我而言,区别在于哪种自然现象最适合其在现实生活中的传播模型(横向)。