回溯法实例-深度优先搜索

如下图所示的图,采用深度优先搜索(DFS)进行遍历:


描述一下问题的解决方案:

在访问其中一个顶点时:

1)  将它标记为已访问;

2)  递归的访问它的所有没有被标记过的邻居顶点。

选择某一顶点为遍历的起始顶点,即可遍历图(连通图)的所有顶点。

boolean[] marked = new boolean[g.V()]; //marked数组大小为图的顶点个数。
public void dfs(Graph g, int v){
    marked[v] = true;
    count++;
    System.out.println("output : " + v);    
	for(int w : g.adj(v)) { //adj[v]为与顶点v相连接的顶点集合。
    	if(!marked[w]) {
    		dfs(g,w);
    	}
    }
}

以dfs(g,4)为例,看一看其调用轨迹:

遍历的顺序为从上到下,圆圈表示该顶点已经访问过,矩形表示还未访问。

非递归的实现有一定的难度,首先能想到的是使用栈来保存,何时入栈和出栈需要花时间来想一想。

如果是进栈前就打印:

public void dfsNoIterationWrong(Graph g, int v,ArrayList<Integer> list){
    	marked[v] = true;
    	stack.push(v);
		System.out.println(v);
    	while(!stack.isEmpty()) {
    		int top = stack.pop();
    		for(int w : g.adj(top)) {
    			if(!marked[w]) {
    				marked[w] = true;
    	    		System.out.println(w);
    				stack.push(w);
    			}
    		}
    	}
    	if(allMarked(marked)){
    		System.out.println(list);
    	}
}

结果: 0 1 2 5 6 4 3

这样写是错误的。这样既不是深度也不是广度搜索。第一轮0的邻接节点1、2、5、6的输出顺序没错,接下来会先打印顶点6的邻接结点4,因为此时6位于栈顶。广度优先搜索正确的方法是使用队列。

正确的算法如下:
public void dfsNoIteration(Graph g, int v,ArrayList<Integer> list){
    	System.out.println(v);
    	marked[v] = true;
    	stack.push(v);
		boolean hasUnvisitedNeigbor;
    	while(!stack.isEmpty()) {
    		int top = stack.peek(); //先不出栈
    		hasUnvisitedNeigbor = false;
    		for(int w : g.adj(top)) {
    			if(!marked[w]) {
    				System.out.println(w);
    				marked[w] = true;
    				stack.push(w);
    				hasUnvisitedNeigbor = true;
    				break;
    			}
    		}
    		if(!hasUnvisitedNeigbor) { //表示top的邻接顶点已经全部处理完
    			stack.pop();
    		}
    	}
    	
    	if(allMarked(marked)){
    		System.out.println(list);
    	}
}
输出结果:0 1 2 5 3 4 6
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值