遍历树/图时,广度优先和深度优先的区别是什么?提供任何编码或伪代码示例都可以。
遍历树/图时,广度优先和深度优先的区别是什么?提供任何编码或伪代码示例都可以。
这两个术语区分了遍历树的两种不同方式。
最好是直接展示它们之间的差异。考虑下面这棵树:
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
两种遍历顺序的区别在于所选择的容器
不同。
递归实现如下:
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
这是一种深度优先的变体,其中我在回溯树之前不会对每个节点执行操作。然而,在下行过程中,我已经访问了更高的节点以查找它们的子节点。
如果使用递归实现,这种遍历方式相当自然(请使用上面的“替代时间”行,而不是第一个“工作”行),如果使用显式堆栈,也不会太难,但我将把它留作练习。
A, B, D, C, E, F
-首个呈现的),中缀遍历(D, B, A, E, C, F
-用于排序:将其作为AVL树添加,然后读取中缀表达式)或后缀遍历(D, B, E, F, C, A
-备选项呈现)。这些名称由您处理根节点的位置给出。需要注意的是,中缀遍历只对二叉树真正有意义。@batbrat 这些就是名称了……考虑到您提问的时间,您可能已经知道了。 - Theraot这张图片应该让你了解词语广度和深度的使用背景。
深度优先搜索算法会尽可能快地远离起点。
它通常使用一个栈
来记住在到达死路时应该去哪里。
遵循的规则:
栈
。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;
}
应用场景:深度优先搜索经常用于模拟游戏(以及现实世界中类似游戏的情况)。在一个典型的游戏中,你可以选择几个可能的行动。每个选择都会导致进一步的选择,每个进一步的选择都会导致更多的选择,以此类推形成一个越来越庞大的树状图。
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撰写的相关数据结构书籍中的“图”章节。
给定这个二叉树:
广度优先遍历:
从左到右遍历每一层。
"我是 G,我的孩子是 D 和 I,我的孙子是 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 上这篇简单的解释,它介绍了深度优先遍历方法及其常见用途:
“中序遍历(In-Order Traversal)将[二叉搜索树]中的值按顺序打印出来。”
“前序遍历(Pre-order traversal)用于创建[二叉搜索树]的副本。”
“后序遍历(Postorder traversal)用于删除[二叉搜索树]。”
https://www.quora.com/What-is-the-use-of-pre-order-and-post-order-traversal-of-binary-trees-in-computing