数据结构与算法系列二十九(图深度优先搜索)

129 阅读4分钟

1.思考

上一篇:数据结构与算法系列二十八(图广度优先搜索) ,我们利用广度优先搜索实现了求最短路径的问题。关于图的常见算法,还有图的深度优先搜索算法。

那么这一篇我们来实现图的深度优先搜索算法。关于图深度优先搜索算法实现,主要会用到递归、以及回溯算法思想。你可以想象一下你正在走迷宫,每个路口都可能有多个岔路:

  • 你可以选择任意一个岔路走下去
  • 如果找到了目标地点(顶点),那么达到目的,搜索过程结束
  • 如果找不到目标地点(顶点),那么退回到上一个岔路口,选择另外一条岔路再走下去。
  • 重复该过程,直到找到目标地点为止
  • 以上就是图深度优先搜索以及回溯的思想,我们稍后通过递归代码实现
#考考你:
1.你知道图的深度优先搜索算法的核心思想吗
2.你能用java语言实现图的深度优先搜索吗

2.案例

2.1.图的定义

/**
 * 无向图-->邻接表存储
 */
class DfsGraph{
​
    /**
     * 顶点个数
     */
    private int v;
​
    /**
     * 邻接表:每个顶点对应一个链表
     */
    private LinkedList<Integer> adj[];
​
    /**
     * 构造方法,根据顶点个数定义图
     * @param v
     */
    public DfsGraph(int v){
        this.v = v;
        this.adj = new LinkedList[v];
​
        // 初始化顶点链表
        for(int i = 0; i < v; i++){
            adj[i] = new LinkedList<Integer>();
        }
​
    }
​
    /**
     * 建立顶点之间的关系
     * @param s
     * @param t
     */
    public void addEdge(int s, int t){
        // 无向图
        // 每一条边需要存储两次
        adj[s].add(t);
        adj[t].add(s);
​
    }
    
}

2.2.深度优先搜索

/**
* 标记是否找到了终止顶点(递归终止条件)
*/
public boolean found = false;
​
/**
* 广度优先搜索
*  1.搜索从起始顶点 s,到终止顶点t的最短路径
* @param s  起始顶点
* @param t  终止顶点
*/
public void dfs(int s, int t){
  // 递归终止条件
  found = false;
​
  // 记录访问过顶点
  boolean []visited = new boolean[v];
​
  // 记录搜索路径
  int []prev = new int[v];
  for(int i = 0; i < v; i++){
      prev[i] = -1;
  }
​
  // 深度优先搜索(递归实现)
  recurDfs(s,t,visited,prev);
​
   // 输出搜索结果路径
   outSToTPath(prev,s,t);
​
}
​
/**
* 递归实现深度优先搜索
* @param s  开始顶点
* @param t  终止顶点
* @param visited  标记顶点是否访问过
* @param prev  搜索路径
*/
private void recurDfs(int s,int t,boolean []visited,int []prev){
​
 // 递归终止条件成立(已经找到目标顶点)
 if(found == true){return;}
​
 // 将顶点标记为已经访问过了
 visited[s] = true;
​
 // 找到目标顶点
 if(s == t){
   found = true;
   // 是目标终止顶点,深度优先搜索结束
   System.out.println("顶点【" + 0 + "】到顶点【" + t + "】搜索结果:");
   return;
 }
​
 // 循环遍历每个邻接表,在邻接表访问中,递归访问
 for(int i = 0; i < adj[s].size(); i++){
​
   // 如果已经发现目标顶点了,就不需要再循环递归
   if(found == true){
      return ;
   }
​
  int q = adj[s].get(i);
  if(!visited[q]){
  prev[q] = s;
​
  // 记录搜索路径
  System.out.println("正在从顶点【" + s + "】访问顶点【" + q + "】");
​
  // 递归
  recurDfs(q,t,visited,prev);
​
 }
​
}
​
}

2.3.辅助打印输出

/**
* 递归打印输出搜索路径
* @param prev  搜索路径
* @param s  起始顶点
* @param t  终止顶点
*/
private void outSToTPath(int[] prev, int s, int t){
​
  if(prev[t] != -1 && t != s){
     outSToTPath(prev, s, prev[t]);
  }
​
  // 打印输出
  System.out.print(t + "-->");
​
}

2.4.测试代码

/**
* 构建图,顶点:0 1 2 3 4 5 ,详情如下:
 0 + + 1 + + 2
 +    +    +
 +    +    +
 3 + + 4 + + 5
*/
public static void main(String[] args) {
​
  // 1.创建6个顶点图
  DfsGraph g = new DfsGraph(6);
​
  // 2.建立顶点之间关系
  // 2.1.顶点:0  1 ;0 3
  g.addEdge(0,1);
  g.addEdge(0,3);
​
  // 2.2.顶点:1 2;1 4
  g.addEdge(1,2);
  g.addEdge(1,4);
​
  // 2.3.顶点:2 5
  g.addEdge(2,5);
​
 // 2.4.顶点:3 4
 g.addEdge(3,4);
​
 // 2.5.顶点:4 5
 g.addEdge(4,5);
​
 // 3.开始深度优先搜索
 int s = 0;
 int t = 3;
 System.out.println("顶点【" + s + "】到顶点【" + t + "】搜索过程:");
 g.dfs(s, t);
​
 }
​
}

2.5.测试结果

D:\02teach\01soft\jdk8\bin\java com.anan.struct.graph.DFS
顶点【0】到顶点【3】搜索过程:
正在从顶点【0】访问顶点【1】
正在从顶点【1】访问顶点【2】
正在从顶点【2】访问顶点【5】
正在从顶点【5】访问顶点【4】
正在从顶点【4】访问顶点【3】
顶点【0】到顶点【3】搜索结果:
0-->1-->2-->5-->4-->3-->
Process finished with exit code 0