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

21 阅读3分钟

1.思考

这段时间有点忙,翻了一下,整个七月份才写了一篇文章:数据结构与算法系列二十七(图的基本概念与存储) 。关于图原计划是三部曲:基本概念、广度优先搜索代码实现、深度优先搜索代码实现。因为太忙就一直阁下了,这周不加班了,我们把该补上的补上。

那么关于图的一些基本概念,比如说:顶点、度、有向图、无向图等。我们就不多说了,如果你忘记了,可以再看一下上一篇文章。这一篇我们用程序员都喜欢的方式,开门见山,直接上图的广度优先搜索算法实现代码。那么,来吧。

#考考你:
1.你知道图的广度优先搜索算法的核心思想吗
2.你能用java语言实现图的广度优先搜索吗

2.案例

2.1.图的定义

/**
 * 无向图-->邻接表存储
 */
class BfsGraph{
​
    /**
     * 顶点个数
     */
    private int v;
​
    /**
     * 邻接表:每个顶点对应一个链表
     */
    private LinkedList<Integer> adj[];
​
    /**
     * 构造方法,根据顶点个数定义图
     * @param v
     */
    public BfsGraph(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.广度优先搜索

/**
* 广度优先搜索
*  1.搜索从起始顶点 s,到终止顶点t的最短路径
* @param s  起始顶点
* @param t  终止顶点
*/
public void bfs(int s, int t){
  // 起始定点,终止顶点是同一个顶点
  if(s == t){
      return;
  }
​
  // 记录已经访问过的顶点,避免顶点重复访问
  boolean [] visited = new boolean[v];
  visited[s] = true;
​
  // 存储已经被访问过,但是相邻顶点还没有被访问的顶点
  Queue<Integer> queue = new LinkedList<Integer>();
  queue.add(s);
​
 // 记录搜索路径,当从顶点s开始,搜索到顶点t后,prev数组存储的是搜索路径
 // 注意:该搜索路径反向存储,即:prev[w]存储的是,顶点w是从哪一个前驱顶点遍历过来
 // 比如:通过顶点2的邻接表访问到顶点3,那么prev[3]=2
 int[] prev = new int[v];
 for(int i = 0; i < v; i++){
    prev[i] = -1;
 }
​
  // 开始广度优先搜索
  while (queue.size() != 0){
    // 出队
    int w = queue.poll();
​
    // 循环遍历访问顶点w的邻接表
    for(int i = 0; i < adj[w].size(); i++){
       // 取出元素,检查是否已经访问过
       int q = adj[w].get(i);
       // 未访问过
      if(!visited[q]){
      // 记录搜索路径
      System.out.println("正在从顶点【" + w + "】访问顶点【" + q + "】");
      prev[q] = w;
​
      // 判断q顶点,是否是终止顶点t
      if(q == t){
       // 是目标终止顶点,广度优先搜索结束
       System.out.println("顶点【" + s + "】到顶点【" + t + "】搜索结果:");
       outSToTPath(prev, s, t);
       return;
      }
​
     // q顶点不是目标终止顶点
     // 将q顶点标记为已访问过,且相邻顶点未访问
     visited[q] = true;
     queue.add(q);
​
    }// 未访问过if end
​
  }//  for end
​
 }// while end
​
}

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个顶点图
  BfsGraph g = new BfsGraph(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.开始广度优先搜索
 // 3.1.搜索顶点:0 到5的最短路径
 int s = 0;
 int t = 5;
 System.out.println("顶点【" + s + "】到顶点【" + t + "】搜索过程:");
 g.bfs(s, t);
​
}

2.5.测试结果

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