我们可以实施“白色,灰色,黑色”带有堆栈的DF而不是使用递归调用
我正在尝试使用堆栈实现“白色灰色黑色DFS”。
白色黑色的概念下面是:
- 如果尚未访问节点,则为
white
。 - 如果只是将一个节点推入堆栈中,但尚未处理其邻居。 (DFS堆栈不是空的,DFS进程尚未遍及分支孩子),节点被标记为
灰色
。 - 如果处理一个节点及其所有子节点,则标记为
black
。
对于(3):
- 如果DFS到达分支的末端,节点没有任何子节点,则标记节点
black
- 带有递归返回,所有父母节点都可以“回溯”并更改从
灰色
到黑色
现在我想实现同一件事,但是我不使用递归调用,而是使用堆栈来实现DFS遍历。出现一个问题:我无法回溯到父节点以将其标记为black
示例问题在此leetcode链接上: https://leetcode.com/problems/find-eventual-safe-states/
到目前为止,我目前的尝试:
class Solution {
private:
vector<int> visited;
// mark nodes as Not Visited=0; "In DFS Progress" = 1; at terminal, all processed and connected to terminal = 2
// if revisiting In Progress node => a back-edge is found.
bool dfs(vector<vector<int>>& graph, int node, vector<int>& result){
stack<int> dfsStack;
dfsStack.push(node);
while (!dfsStack.empty()){
int currNode = dfsStack.top();
dfsStack.pop();
// if currNode connect to a node in In Progress
if (currNode == 1){
return false;
}
// mark gray, black for nodes in DFS progress, terminal nodes;
if (graph[currNode].size()==0){ // mark terminal node as 2
visited[currNode] = 2;
// set all parents node as 2 ===>>>> HOW TO DO THIS????
}
else
visited[currNode] = 1; // mark node in progress as 1
// process neighbor:
for (int i = 0; i < graph[currNode].size(); i++){
int nextNode = graph[currNode][i];
dfsStack.push(nextNode);
}
}
return true;
}
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
vector<int> result;
visited.resize((graph.size(),0)); // all nodes are not yet visited
for (int node=0; node<graph.size(); node++){
if (dfs(graph, node, result)
result.push_back(node);
}
return result;
}
};
我正在学习,并加深我的理解,并加深我的理解,我有一种用几种方法实施每件事的习惯。
I am trying to implement "White Gray Black DFS" using stack.
The concept of White Gray Black is below:
- if a node is not yet visited, it is
White
. - if a node is just pushed in stack, but its neighbors are not yet processed. (DFS stack is not empty, DFS process has yet traversed to the branch child), the node is marked
Gray
. - if a node and all its child node are processed, it is marked
Black
.
For (3):
- if DFS reaches the end of the branch, the node doesn't have any child nodes, the node is marked
Black
- with recursive return, all parents nodes can be "backtracked" and changed from
Gray
toBlack
Now I want to implement the same thing, but instead of using recursive call, I use stack to implement DFS traversing. A problem arises: I cannot backtrack to parent nodes to mark them as Black
The sample problem is on this Leetcode link: https://leetcode.com/problems/find-eventual-safe-states/
My current attempt so far:
class Solution {
private:
vector<int> visited;
// mark nodes as Not Visited=0; "In DFS Progress" = 1; at terminal, all processed and connected to terminal = 2
// if revisiting In Progress node => a back-edge is found.
bool dfs(vector<vector<int>>& graph, int node, vector<int>& result){
stack<int> dfsStack;
dfsStack.push(node);
while (!dfsStack.empty()){
int currNode = dfsStack.top();
dfsStack.pop();
// if currNode connect to a node in In Progress
if (currNode == 1){
return false;
}
// mark gray, black for nodes in DFS progress, terminal nodes;
if (graph[currNode].size()==0){ // mark terminal node as 2
visited[currNode] = 2;
// set all parents node as 2 ===>>>> HOW TO DO THIS????
}
else
visited[currNode] = 1; // mark node in progress as 1
// process neighbor:
for (int i = 0; i < graph[currNode].size(); i++){
int nextNode = graph[currNode][i];
dfsStack.push(nextNode);
}
}
return true;
}
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
vector<int> result;
visited.resize((graph.size(),0)); // all nodes are not yet visited
for (int node=0; node<graph.size(); node++){
if (dfs(graph, node, result)
result.push_back(node);
}
return result;
}
};
I am learning, and to deepen my understanding, I have a habit of implementing every thing with a few methods.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您递归实现DFS时,递归调用来处理孩子使用呼叫堆栈来记住父节点和父母列表中的当前位置。
当孩子完成后,对父母节点的处理处理将继续,其中包括检测何时没有孩子和父母的任何最终处理,例如“标记黑色”。
您的迭代实现无法正常工作。当您开始处理父母时,您将全部将其孩子推向堆栈,而忘记了父母。堆栈不像递归版本中那样包含进展中的节点。它包含您尚未访问的节点。这意味着您不记得执行任何最终父母处理所需的信息。
您需要通过更改记住的内容来使迭代实现更像递归的实现。有许多不同的方式。例如,您可以像递归版本一样,记住一个节点堆栈和位置堆栈,而是可以记住当前的父母和位置。由于您使用相同类型的节点和位置,因此您甚至可以在同一堆栈上交替使用它们。
但是请注意:您似乎正在使用DFS进行周期检测。由于我们在这里谈论的是额外的并发症,因此我通常使用 a>为此。
When you implement DFS recursively, the recursive call to process the child uses the call stack to remember the parent node and the current position in the parent's list of children.
When the child is complete, processing of the processing of the parent node continues, which includes detecting when there are no more children and any final processing of the parent, like "marking it black".
Your iterative implementation does not work like this. When you start processing the parent, you push all its children on the stack and forget about the parent. The stack doesn't contain the nodes in progress like it does in the recursive version. It contains the nodes that you have yet to visit. That means you didn't remember the information required to do any final parent processing.
You need to make your iterative implementation work more like the recursive one by changing what you remember. There are many different ways. For example, instead of using a stack of nodes to remember all unprocessed children, you can you a node stack and a position stack, to remember the current parent and position in the child list just like the recursive version. Since you are using the same type for nodes and positions, you could even alternate them on the same stack.
But note: You seem to be using DFS for cycle detection. Because of the extra complications that we're talking about here, I usually use Kahn's algorithm for that.