Algorithm 如何用非递归方法实现图的深度优先搜索
我在这个问题上花了很多时间。但是,我只能为树找到非递归方法,或为图找到递归方法 很多教程(我这里不提供这些链接)也没有提供方法。或者教程完全不正确。请帮帮我 更新: 这真的很难描述: 如果我有一个无向图:Algorithm 如何用非递归方法实现图的深度优先搜索,algorithm,graph,depth-first-search,non-recursive,Algorithm,Graph,Depth First Search,Non Recursive,我在这个问题上花了很多时间。但是,我只能为树找到非递归方法,或为图找到递归方法 很多教程(我这里不提供这些链接)也没有提供方法。或者教程完全不正确。请帮帮我 更新: 这真的很难描述: 如果我有一个无向图: 1 / | \ 4 | 2 3 / 1--2--3--1是一个循环 在“将弹出顶点的相邻顶点推入堆栈”步骤中,应按什么顺序推入顶点 如果推送顺序为2,4,3,则堆栈中的顶点为: | | |3| |4| |2| _ 弹出节点后,我们得到的结果是:1->3->
1
/ | \
4 | 2
3 /
1--2--3--1是一个循环
在“将弹出顶点的相邻顶点推入堆栈”步骤中,应按什么顺序推入顶点
如果推送顺序为2
,4
,3
,则堆栈中的顶点为:
| |
|3|
|4|
|2|
_
弹出节点后,我们得到的结果是:1->3->4->2
,而不是1-->3-->2-->4
这是不正确的。我应该添加什么条件来停止此场景?递归是使用调用堆栈存储图形遍历状态的一种方法。您可以显式地使用堆栈,比如通过使用一个类型为
std::stack
的局部变量,那么您就不需要递归来实现DFS,而只需要一个循环。没有递归的DFS基本上与-相同,但是使用a而不是队列作为数据结构
两种方法的线程句柄以及它们之间的差异(确实如此!您将不会以相同的顺序遍历节点!)
迭代法的算法基本上是:
DFS(source):
s <- new stack
visited <- {} // empty set
s.push(source)
while (s is not empty):
current <- s.pop()
if (current is in visited):
continue
visited.add(current)
// do something with current
for each node v such that (current,v) is an edge:
s.push(v)
DFS(来源):
s这不是一个答案,而是一个扩展注释,显示@amit在当前问题版本中对图形的回答中算法的应用,假设1是开始节点,其邻居按2、4、3的顺序推送:
1
/ | \
4 | 2
3 /
Actions Stack Visited
======= ===== =======
push 1 [1] {}
pop and visit 1 [] {1}
push 2, 4, 3 [2, 4, 3] {1}
pop and visit 3 [2, 4] {1, 3}
push 1, 2 [2, 4, 1, 2] {1, 3}
pop and visit 2 [2, 4, 1] {1, 3, 2}
push 1, 3 [2, 4, 1, 1, 3] {1, 3, 2}
pop 3 (visited) [2, 4, 1, 1] {1, 3, 2}
pop 1 (visited) [2, 4, 1] {1, 3, 2}
pop 1 (visited) [2, 4] {1, 3, 2}
pop and visit 4 [2] {1, 3, 2, 4}
push 1 [2, 1] {1, 3, 2, 4}
pop 1 (visited) [2] {1, 3, 2, 4}
pop 2 (visited) [] {1, 3, 2, 4}
因此,应用该算法,按顺序2、4、3推送1的邻居,结果是访问顺序1、3、2、4。无论1的邻居的推送顺序如何,2和3在访问顺序中都是相邻的,因为先访问的将推送另一个未访问的邻居,以及已访问的邻居。我认为您需要使用已访问的[n]
布尔数组,用于检查当前节点是否已访问。DFS逻辑应为:
1) 如果未访问当前节点,请访问该节点并将其标记为已访问
2) 对于所有没有被拜访过的邻居,把他们推到堆栈上
例如,让我们在Java中定义一个GraphNode类:
class GraphNode {
int index;
ArrayList<GraphNode> neighbors;
}
类图形节点{
整数指数;
ArrayList邻居;
}
这是无递归的DFS:
void dfs(GraphNode node) {
// sanity check
if (node == null) {
return;
}
// use a hash set to mark visited nodes
Set<GraphNode> set = new HashSet<GraphNode>();
// use a stack to help depth-first traversal
Stack<GraphNode> stack = new Stack<GraphNode>();
stack.push(node);
while (!stack.isEmpty()) {
GraphNode curr = stack.pop();
// current node has not been visited yet
if (!set.contains(curr)) {
// visit the node
// ...
// mark it as visited
set.add(curr);
}
for (int i = 0; i < curr.neighbors.size(); i++) {
GraphNode neighbor = curr.neighbors.get(i);
// this neighbor has not been visited yet
if (!set.contains(neighbor)) {
stack.push(neighbor);
}
}
}
}
void dfs(图形节点){
//健康检查
if(node==null){
返回;
}
//使用哈希集标记已访问的节点
Set=newhashset();
//使用堆栈帮助深度优先遍历
堆栈=新堆栈();
栈推(节点);
而(!stack.isEmpty()){
GraphNode curr=stack.pop();
//当前节点尚未访问
如果(!set.contains(curr)){
//访问节点
// ...
//将其标记为已访问
集合。添加(当前);
}
for(int i=0;i
我们可以使用相同的逻辑递归执行DFS、克隆图等。好的。如果您仍在寻找java代码
dfs(Vertex start){
Stack<Vertex> stack = new Stack<>(); // initialize a stack
List<Vertex> visited = new ArrayList<>();//maintains order of visited nodes
stack.push(start); // push the start
while(!stack.isEmpty()){ //check if stack is empty
Vertex popped = stack.pop(); // pop the top of the stack
if(!visited.contains(popped)){ //backtrack if the vertex is already visited
visited.add(popped); //mark it as visited as it is not yet visited
for(Vertex adjacent: popped.getAdjacents()){ //get the adjacents of the vertex as add them to the stack
stack.add(adjacent);
}
}
}
for(Vertex v1 : visited){
System.out.println(v1.getId());
}
}
dfs(顶点开始){
Stack Stack=new Stack();//初始化堆栈
List visted=new ArrayList();//维护已访问节点的顺序
stack.push(启动);//启动
而(!stack.isEmpty()){//检查堆栈是否为空
顶点弹出=stack.pop();//弹出堆栈顶部
如果(!visted.contains(popped)){//如果顶点已被访问,则返回
已访问。添加(弹出);//将其标记为已访问,因为它尚未访问
for(顶点邻接:popped.getAdjancets()){//获取顶点的邻接,并将其添加到堆栈中
叠加(相邻);
}
}
}
对于(顶点v1:已访问){
System.out.println(v1.getId());
}
}
递归算法对DFS非常有效,因为我们尝试尽可能深入,也就是说,一旦我们找到一个未探测的顶点,我们将立即探测它的第一个未探测的邻居。一旦找到第一个未探测的邻居,您就需要打破for循环
for each neighbor w of v
if w is not explored
mark w as explored
push w onto the stack
BREAK out of the for loop
我认为这是一个关于空间的优化DFS。如果我错了,请纠正我
s = stack
s.push(initial node)
add initial node to visited
while s is not empty:
v = s.peek()
if for all E(v,u) there is one unvisited u:
mark u as visited
s.push(u)
else
s.pop
使用堆栈并按照递归过程中调用堆栈的方式实现-
其思想是在堆栈中推送一个顶点,然后推送其相邻的顶点,该顶点存储在顶点索引处的邻接列表中,然后继续此过程,直到我们无法在图中进一步移动,现在,如果我们不能在图中向前移动,那么我们将移除当前位于堆栈顶部的顶点,因为它无法将我们带到任何未访问的顶点上
现在,使用堆栈,我们注意到只有当所有可以从当前顶点探索的顶点都被访问时,顶点才会从堆栈中移除,这是由递归过程自动完成的
前-
(0(1)(2(4)2)(33)1)0)(6(5)(7)6)
上面的括号显示了顶点在堆栈上的添加顺序和从堆栈中删除的顺序,因此,只有在完成可以访问的所有顶点后,才会关闭顶点的括号
(这里我使用邻接表表示),并用C++(STL)
作为列表向量(Vector > ADJLIST)实现。
void DFSUsingStack()
void DFSUsingStack() {
/// we keep a check of the vertices visited, the vector is set to false for all vertices initially.
vector<bool> visited(AdjList.size(), false);
stack<int> st;
for(int i=0 ; i<AdjList.size() ; i++){
if(visited[i] == true){
continue;
}
st.push(i);
cout << i << '\n';
visited[i] = true;
while(!st.empty()){
int curr = st.top();
for(list<int> :: iterator it = AdjList[curr].begin() ; it != AdjList[curr].end() ; it++){
if(visited[*it] == false){
st.push(*it);
cout << (*it) << '\n';
visited[*it] = true;
break;
}
}
/// We can move ahead from current only if a new vertex has been added on the top of the stack.
if(st.top() != curr){
continue;
}
st.pop();
}
}
}
numv = 1000
print('vertices =', numv)
G = [Vertex(i) for i in range(numv)]
def dfs(source):
s = []
visited = set()
s.append((source,None))
time = 1
space = 0
while s:
time += 1
current, index = s.pop()
if index is None:
visited.add(current)
index = 0
# vertex has all edges possible: G is a complete graph
while index < len(G) and G[index] in visited:
index += 1
if index < len(G):
s.append((current,index+1))
s.append((G[index], None))
space = max(space, len(s))
print('time =', time, '\nspace =', space)
dfs(G[0])
time = 2000
space = 1000
private void DFS(int v,boolean[] visited){
visited[v]=true;
Stack<Integer> S = new Stack<Integer>();
S.push(v);
while(!S.isEmpty()){
int v1=S.pop();
System.out.println(adjLists.get(v1).name);
for(Neighbor nbr=adjLists.get(v1).adjList; nbr != null; nbr=nbr.next){
if (!visited[nbr.VertexNum]){
visited[nbr.VertexNum]=true;
S.push(nbr.VertexNum);
}
}
}
}
public void dfs() {
boolean[] visited = new boolean[adjLists.size()];
for (int v=0; v < visited.length; v++) {
if (!visited[v])/*This condition is for Unconnected Vertices*/ {
System.out.println("\nSTARTING AT " + adjLists.get(v).name);
DFS(v, visited);
}
}
}
// From non-recursive "DFS"
for (auto i&: adjacent) {
if (!visited(i)) {
stack.push(i);
}
}
// From recursive DFS
for (auto i&: adjacent) {
if (!visited(i)) {
dfs(i);
}
}
from collections import defaultdict
class Graph(object):
adj_list = defaultdict(list)
def __init__(self, V):
self.V = V
def add_edge(self,u,v):
self.adj_list[u].append(v)
def DFS(self):
visited = []
instack = []
disc = []
fini = []
for t in range(self.V):
visited.append(0)
disc.append(0)
fini.append(0)
instack.append(0)
time = 0
for u_ in range(self.V):
if (visited[u_] != 1):
stack = []
stack_recorder = []
stack.append(u_)
while stack:
u = stack.pop()
visited[u] = 1
time+=1
disc[u] = time
print(u)
stack_recorder.append(u)
flag = 0
for v in self.adj_list[u]:
if (visited[v] != 1):
flag = 1
if instack[v]==0:
stack.append(v)
instack[v]= 1
if flag == 0:
time+=1
temp = stack_recorder.pop()
fini[temp] = time
while stack_recorder:
temp = stack_recorder.pop()
time+=1
fini[temp] = time
print(disc)
print(fini)
if __name__ == '__main__':
V = 6
G = Graph(V)
#==============================================================================
# #for case 1
# G.add_edge(0,1)
# G.add_edge(0,2)
# G.add_edge(1,3)
# G.add_edge(2,1)
# G.add_edge(3,2)
#==============================================================================
#==============================================================================
# #for case 2
# G.add_edge(0,1)
# G.add_edge(0,2)
# G.add_edge(1,3)
# G.add_edge(3,2)
#==============================================================================
#for case 3
G.add_edge(0,3)
G.add_edge(0,1)
G.add_edge(1,4)
G.add_edge(2,4)
G.add_edge(2,5)
G.add_edge(3,1)
G.add_edge(4,3)
G.add_edge(5,5)
G.DFS()