使用DFS和BFS统计省份数量

深度优先

广度优先

我们用一个二维数组来存储城市与城市之间的关系,若从城市i到城市j直接相连或间接相连,那么二维数组的[i][j]和[j][i]均为1,若无论如何也无法从一座城市抵达另外一座城市,则对应二维数组中两个值为0.约定城市到自己之间是连接的。

先来看看DFS.首先我们需要遍历一个存储了城市之间连通信息的二维数组,然后我们还需要一个数组来打标记,若某一座城市在遍历中已经被访问,那么以后遍历时,我们就不需要再访问了。由于二维数组长度就是城市数量,因此标记数组只需要开这么大。遍历时,我们就用两个for循环嵌套(这里涉及函数的调用,但本质上就是两个for循环嵌套),if判断时,我们不仅需要判断二维数组中两座城市之间是否相连,我们还需要判断在标记数组中是否被访问,判断后者可以减少时间复杂度。

 1 private static void dfs(int i, int cities, boolean[] visited, int[][] citiesConnected) {
 2         for(int j = 0;j < cities;++j){
 3             if(citiesConnected[i][j] == 1 && !visited[j]){
 4                 visited[j] = true;  //有关联,那么就打标记
 5                 //然后递归,因为找到了所有跟i直接相连的城市,我们还需要找没有跟i直接相连的城市
 6                 //也就是跟j直接相连的城市
 7                 dfs(j, cities, visited, citiesConnected);  
 8             }
 9         }
10     }
 1 private static int getProvincesByDepth(int[][] citiesConnected) {
 2         int cities = citiesConnected.length;
 3         int provinces = 0;
 4         boolean[] visited = new boolean[cities];
 5         for(int i = 0;i < cities;++i){
 6             if(!visited[i]){   //因为在dfs方法里很多城市之间都打上了标记,因此这里其实会跳过很多城市
 7                 dfs(i, cities, visited, citiesConnected);
 8                 ++provinces;
 9             }
10         }
11         return provinces;
12     }

再来看看广度优先:

我们就以某一座城市为中心,一圈一圈地挨个遍历,然后把这个圈子慢慢变大。所以这样一来一个while循环就足可以遍历完所有与这座城市相连的城市了。然后在外层for循环我们再找其他省份的城市。

 1 private static void bfs(int i, int cities, boolean[] visited, int[][] citiesConnected) {
 2         Queue<Integer> queue = new LinkedList<Integer> ();
 3         queue.offer(i);
 4         while(!queue.isEmpty())  //这么一个循环,就可以实现以某一座城市为中心,呈辐射状向四周散开全部遍历
 5         {
 6             int temp = queue.poll();
 7             visited[temp] = true;
 8             for(int j = 0;j < cities;++j){
 9                 if(citiesConnected[i][j] == 1 && !visited[j]) {
10                     queue.offer(j);
11                 }
12             }
13         } //循环结束后再去找没有被标记的城市实行同样的操作
14     }
 1 private static int getProvincesByWidth(int[][] citiesConnected) {
 2         int cities = citiesConnected.length;
 3         int provinces = 0;
 4         boolean[] visited = new boolean[cities];
 5         for(int i = 0;i < cities;++i){
 6             if(!visited[i]){
 7                 bfs(i, cities, visited, citiesConnected);
 8                 ++provinces;
 9             }
10             
11         }
12         return provinces;
13     }

来看看运行效果:

 

 贴一波完整代码:

 1 package com.hw.list0710;
 2 
 3 import java.util.LinkedList;
 4 import java.util.Queue;
 5 import java.util.Scanner;
 6 
 7 public class GroupMerge {
 8     private static int getProvincesByDepth(int[][] citiesConnected) {
 9         int cities = citiesConnected.length;
10         int provinces = 0;
11         boolean[] visited = new boolean[cities];
12         for(int i = 0;i < cities;++i){
13             if(!visited[i]){   //因为在dfs方法里很多城市之间都打上了标记,因此这里其实会跳过很多城市
14                 dfs(i, cities, visited, citiesConnected);
15                 ++provinces;
16             }
17         }
18         return provinces;
19     }
20 
21     private static int getProvincesByWidth(int[][] citiesConnected) {
22         int cities = citiesConnected.length;
23         int provinces = 0;
24         boolean[] visited = new boolean[cities];
25         for(int i = 0;i < cities;++i){
26             if(!visited[i]){
27                 bfs(i, cities, visited, citiesConnected);
28                 ++provinces;
29             }
30             
31         }
32         return provinces;
33     }
34 
35     /**
36      * 深度优先
37      * @param i
38      * @param cities
39      * @param visited
40      * @param citiesConnected
41      */
42     private static void dfs(int i, int cities, boolean[] visited, int[][] citiesConnected) {
43         for(int j = 0;j < cities;++j){
44             if(citiesConnected[i][j] == 1 && !visited[j]){
45                 visited[j] = true;  //有关联,那么就打标记
46                 //然后递归,因为找到了所有跟i直接相连的城市,我们还需要找没有跟i直接相连的城市
47                 //也就是跟j直接相连的城市
48                 dfs(j, cities, visited, citiesConnected);  
49             }
50         }
51     }
52 
53     /**
54      * 广度优先
55      * @param i
56      * @param cities
57      * @param visited
58      * @param citiesConnected
59      */
60     private static void bfs(int i, int cities, boolean[] visited, int[][] citiesConnected) {
61         Queue<Integer> queue = new LinkedList<Integer> ();
62         queue.offer(i);
63         while(!queue.isEmpty())  //这么一个循环,就可以实现以某一座城市为中心,呈辐射状向四周散开全部遍历
64         {
65             int temp = queue.poll();
66             visited[temp] = true;
67             for(int j = 0;j < cities;++j){
68                 if(citiesConnected[i][j] == 1 && !visited[j]) {
69                     queue.offer(j);
70                 }
71             }
72         } //循环结束后再去找没有被标记的城市实行同样的操作
73     }
74 
75     public static void main(String[] args) {
76         int[][] city = null;
77         Scanner s = new Scanner(System.in);
78         System.out.println("长度:");
79         int length = s.nextInt();
80         city = new int[length][length];
81         System.out.println("输入数据:");
82         for(int i = 0;i < length;++i) {
83             for(int j = 0;j < length;++j) {
84                 city[i][j] = s.nextInt();
85             }
86         }
87         s.close();
88         int res1 = getProvincesByDepth(city);
89         System.out.println("使用深度优先:共有"+res1+"个省份");
90         int res2 = getProvincesByWidth(city);
91         System.out.println("使用广度优先:共有"+res2+"个省份");
92     }
93 }

 

posted @ 2021-07-19 23:28  EvanTheBoy  阅读(109)  评论(0)    收藏  举报