无向图的Depth-first search和Breadth-first Search

1. Depth-first search和Breadth-first search有什么用?

从它们的名字中可以看出,这两者都是图的搜索算法。不同于树的搜索,图搜索的基本思路是遍历每一个vertex,直到找到我们想要的结果。这两个算法实际上都是遍历。
前面我们建立起了图结构,我们可以直接知道每个vertex相邻近的vertex有哪些,但是不能直接知道任意两个vertex之间是什么关系(比如它们之间的路径啊,是不是相连啊等等)。基于 Depth -first search和Breadth-first search算法,我们可以高效地 解决这一问题。

2. Depth-first search的应用一:查找路径。

给定一个源头vertex(假设叫s),和任意一个vertex,他们之间的连接路径是怎样的?为了解决这一问题,我们可以用 Depth-first search算法。思路如下:
首先新建两个数组,一个boolean类型,叫marked,用来记录vertex是不是被检验过(为了避免重复);一个int类型,叫edgeTo,用于记录某vertex上面连接着啥玩意儿。在遍历与s相关vertex的同时(即 Depth-first search),我们顺便操作一下这两个数组。这样结束的时候,所有路径信息都被记录在edgeTo数组里面,我们可以从非常方便的查找某vertex到s的路径信息。代码如下:

public class DepthFirstPath{
    private boolean[] marked;
    //edgeTo数组,用于记录路径信息。
    private int[] edgeTo;
    private final int s;

    public DepthFirstPath(Graph G, int s)
    {
        this.s = s;
        //初始化marked以及edgeTo数组,长度就是G图内vertex的个数。
        marked = new boolean[G.V()];
        edgeTo = new int[G.V()];
        dfs(G, s);
    }
    
    private void dfs(Graph G, int v)
    {
        marked[v] = true;
        for(int w : G.adj(v))
            if(!marked[w])
            {
                //这个便是dfs的顺便操作,在遍历相关vertex的同时,
                //顺便操作了edgeTo数组。
                edgeTo[w] = v;
                dfs(w);
            }
    }

    public boolean hasPath(int v)
    //未被标记(marked值为false),说明该vertex跟s不相连,自然没有path。
    { return marked[v]; }

    public Iterable path(int v)
    {
        if(!hasPath(v)) return null;
        Stack path = new Stack<>();
        for(int x = v; x != s; x = edgeTo[x])
            //路径信息提取出来,保存到stack里面。
            path.push(x);
        path.push(s);
        return path;
    }
}

3. Breadth-first search的应用一:查找路径。

Breadth-first search也是一种遍历所有元素的算法。从它的名字中就可以看出,这种算法是讲究宽度,而不是深度。Depth-first search是沿某一支不断深入下去,到头了就再回到上一节点再往下找。而Breadth-first search是很多支一起,一层层的往下进展的。当然也可以顺便操作edgeTo数组,记录路径信息。

public class BreadthFirstPaths
{
	private int[] edgeTo;
	private boolean[] marked[];
	private int s;
	
	public BreadthFirstPaths(Graph G, int s)
	{
		maeked = new boolean[G.V()];
		edgeTo = new int[G.V()];
		this.s = s;
		bfs(s);
	}
	
	private void bsf(Graph G, int s)
	{
		marked[s] = true;
		Queue queue = new Queue<>();
		queue.enqueue(s);
		while(!queue.isEmpty())
		{
			int v = queue.dequeue();
			for(int w : G.adj())
				if(!marked[w])
				{
					queue.enqueue(w);
					edgeTo[w] = v;
					marked[w] = true;
				}								
		}
	}
	
	public boolean hasPathTo(int v)  
    { return marked[v]; }  
      
    public Iterable pathTo(int v)  
    {  
        if(!hasPathTo(v)) return null;  
        Stack path = new Stack<>();  
        for(int x = v; x != s; x = edgeTo[v])  
            path.push(x);  
        path.push(s);  
        return path;  
    }  
}                                                

4. Depth-first search的应用二:相连的vertex。

任意给出一些vertex,如何判断它们是否相连?Depth-first search算法可以以解决这个问题,代码如下:

public class CC
{
	//ID数组代替edgeTo数组,相连接的vertex的ID值一致。
	private int[] ID;
	private boolean[] marked;
	private int count;
	
	public CC(Graph G)
	{
		ID = new int[G.V()];
		marked = new boolean[G.V()];
		for(int s = 0; s < G.V(); s++)
			if(!marked[s])
			{
				dfs(G, s);
				count++;
			}
	}
	
	private void dfs(Graph G, int v)
	{
		marked[v] = true;
		ID[v] = count;
		for(int w : G.adj[v])
			if(!marked[w])
			{				
				dfs(w);
			}
	}
	
	//判断两个vertex是否相连,就是看它们的ID是否一致。
	public boolean connected(int v, int w)
	{ return ID[v] == ID[w]; }
}

你可能感兴趣的:(个人总结)