算法 Full-DFS 输出不如预期。

huangapple go评论72阅读模式
英文:

Algorithm Full-DFS output not as expected

问题

The result [4, 2, 3, 1, 0] is because of the order in which the Depth-First Search (DFS) algorithm explores the nodes in your adjacency list. DFS starts at node 0 and explores its adjacent nodes, which are 1. Then it goes to node 1 and explores its adjacent nodes [2, 3], and so on.

So, the order of exploration follows the order of the adjacency list. In your case, it's [4, 2, 3, 1, 0], which is entirely valid based on how DFS works.

Whether this result is meaningful or not depends on the specific problem you are trying to solve with DFS and the structure of your graph. It's a valid DFS traversal order, but whether it's meaningful for your application depends on the context.

英文:

I copied Python code DFS and full-DFS from 6.006 and this code make me confused, its result not run as expected, please help me, thank you

    def dfs(Adj, s, parent = None, order = None):
    if parent is None:
        parent = [None for v in Adj] 
        parent
展开收缩
= s order = [] print(f's:{s}') print(f'Adj
展开收缩
:{Adj
展开收缩
}') for v in Adj
展开收缩
: if parent[v] is None: print(f'parent[{v}] is None:{parent[v]}') parent[v] = s dfs(Adj, v, parent, order) order.append(s) print(f'dfs order:{order}') print(f'dfs parent:{order}') return parent, order def full_dfs(Adj): parent = [None for v in Adj] order = [] print(f'full_dfs:{parent}') print(f'full_dfs:{len(Adj)}') print(f'full_dfs:{range(len(Adj))}') for v in range(len(Adj)): print(f'{v}') if parent[v] is None: parent[v] = v dfs(Adj, v, parent, order) return parent, order adj = [[1],[2,3],[4],[4],[]] par,order = full_dfs(adj) print(f'{par}') print(f'{order}') # #*******************Output*************************** #full_dfs:[None, None, None, None, None] #full_dfs:5 #full_dfs:range(0, 5) #0 #s:0 #Adj
展开收缩
:[1] #parent[1] is None:None #s:1 #Adj
展开收缩
:[2, 3] #parent[2] is None:None #s:2 #Adj
展开收缩
:[4] #parent[4] is None:None #s:4 #Adj
展开收缩
:[] #dfs order:[4] #dfs parent:[4] #dfs order:[4, 2] #dfs parent:[4, 2] #parent[3] is None:None #s:3 #Adj
展开收缩
:[4] #dfs order:[4, 2, 3] #dfs parent:[4, 2, 3] #dfs order:[4, 2, 3, 1] #dfs parent:[4, 2, 3, 1] #dfs order:[4, 2, 3, 1, 0] #dfs parent:[4, 2, 3, 1, 0] #1 #2 #3 #4 #[0, 0, 1, 1, 2] #[4, 2, 3, 1, 0] # # #** Process exited - Return Code: 0 ** #Press Enter to exit terminal

My question is, why its result is [4, 2, 3, 1, 0] rather than [4,2,1,0] or [4,3,1,0], because Depth first right?

In my opinion, [4, 2, 3, 1, 0] meaningless, do you agree?

答案1

得分: 2

首先,您的代码访问所有节点。 "深度优先" 不意味着 "仅首个"。它意味着在查看兄弟节点之前,它会首先查看子节点。但它的目的是访问所有节点。

您的代码会访问所有节点,因为 parent 记录了哪些节点已经被访问,哪些尚未被访问,如果它们尚未被访问,那么 full_dfsdfs 中的循环会确保它们被访问。当一个节点被传递给 dfs 时,它最终会被附加到 order,因此预期所有节点最终都会出现在该列表中。

其次,只有当从该节点可达的所有其他节点都已被访问(通过递归)时,节点才会被添加到 order。这就是所谓的后序遍历,因为对节点的操作在其所有后继/子节点上执行之后才执行。

现在来看示例图:

算法 Full-DFS 输出不如预期。

dfs 递归调用从节点 0 到 1 到 2 到 4。在那个阶段,没有更多的后继节点了,所以 4 被附加到 order,并且最深的 dfs 调用返回到 dfs 的执行上下文,其中当前节点是 2。同样,在那里我们发现没有其他后继节点,因此 2 被附加到 order,并且该 dfs 调用也返回。我们回到了当前节点是 1 的 dfs 的执行上下文。

在这里,我们有另一个后继节点(循环的第二次迭代),因此会进行另一个递归调用,其中 3 是当前节点。尽管此节点有一个后继节点(4),但该节点已经被访问过(其 parent 已经设置),因此 3 被附加到 order,并且执行返回到当前节点为 1 的执行上下文。

对于节点 1,没有其他后继节点,因此将 1 附加到 order,并且 dfs 返回到 dfs 的原始执行上下文,其中当前节点是 0。此节点没有其他后继节点,因此将 0 附加到 order

我们可以将这个过程可视化一下,其中每个 "盒子" 表示函数的执行上下文。执行从上到下进行。当函数返回时,其执行上下文结束(盒子关闭),执行在周围的 "盒子" 中继续:

希望这澄清了该过程,以及为什么在从 0 开始的情况下,您会得到 [4, 2, 3, 1, 0] 作为输出:这是您的图的后序深度优先遍历。

英文:

First of all, your code visits all nodes. "depth-first" does not mean "first-only". It means that before looking to sibling nodes, it will first look to children nodes. But its purpose is to visit all nodes.

All nodes are visited by your code because parent records which nodes are visited, and which not yet, and if they are not yet visited, the loops in both full_dfs and dfs ensure they are. And when a node is given to dfs, it eventually gets appended to order, so it is expected that all nodes end up in that list.

Secondly, a node is only added to order when all other nodes that are reachable from that node have been visited (through recursion). This is what is called a post-order traversal, since the action on the node is performed after the same action has been done on all its successors/children.

Now to the example graph:

算法 Full-DFS 输出不如预期。

dfs recursive calls are made to go from node 0 to 1 to 2 to 4. At that stage there are no more successor nodes, so 4 is appended to order, and that deepest dfs call returns to get back to the execution context of dfs where the current node is 2. Also there we find there are no other successors, so 2 is appended to order and also that dfs call returns. We get back to the execution context of dfs where the current node is 1.

Here we have another successor (second iteration of the loop), and so another recursive call is made where 3 is the current node. Although this node has a successor (4), that node has already been visited (its parent has been set), so 3 is appended to order and execution returns to the execution context where 1 is the current node.

For node 1 there are no other successors, so 1 is appended to order and dfs returns to the original execution context of dfs where the current node is 0. This node has no other successors, so 0 is appended to order.

We can visualise this process a bit where each "box" represents an execution context of a function. Execution goes from top to bottom. When a function returns, its execution context ends (the box closes) and execution continues in the surrounding "box":

+-- full_dfs() --------------------------------+
|  parent[0] = 0                               | 
|  +-- dfs(s=0) ----------------------------+  |
|  |  parent[1] = 0                         |  |
|  |  +-- dfs(s=1) ----------------------+  |  |
|  |  |  parent[2] = 1                   |  |  |
|  |  |  +-- dfs(s=2) ----------------+  |  |  |
|  |  |  |  parent[4] = 2             |  |  |  |
|  |  |  |  +-- dfs(s=4) ----------+  |  |  |  |
|  |  |  |  | order.append(4)      |  |  |  |  |
|  |  |  |  +----------------------+  |  |  |  |
|  |  |  |  order.append(2)           |  |  |  |
|  |  |  +----------------------------+  |  |  |
|  |  |  parent[3] = 1                   |  |  |
|  |  |  +-- dfs(s=3) ----------------+  |  |  |
|  |  |  |  order.append(3)           |  |  |  |
|  |  |  +----------------------------+  |  |  |
|  |  |  order.append(1)                 |  |  |
|  |  +----------------------------------+  |  |
|  |  order.append(0)                       |  |
|  +----------------------------------------+  |
+----------------------------------------------+

Hope this clarifies the process and why you get [4, 2, 3, 1, 0] as output: it is the post-order DFS traversal for your graph when starting at 0.

huangapple
  • 本文由 发表于 2023年6月25日 19:35:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/76550195.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定