對於上圖很顯然連通份量爲1,對於下圖連通份量個數爲2java
經過上一小節dfs遍歷的過程咱們知道依次dfs就是一個連通份量,由於dfs只有走到無路可走纔會回退,因此咱們只須要記錄一下dfs次數便可,有以下代碼數組
public class UndirectedGraphDFSCC { private UndirectedGraph graph; private boolean[] visited; private int ccCount;//連通份量 public UndirectedGraphDFSCC(UndirectedGraph graph){ this.graph = graph; visited = new boolean[graph.vertexNum()]; //可能有多個連通份量,因此得for for(int v=0;v<graph.vertexNum();v++){ if(!visited[v]){ dfs(v); ccCount++; } } } public int getCcCount(){ return ccCount; } private void dfs(int v){ visited[v] = true; for(int w:graph.adj(v)) { if(!visited[w]){ dfs(w); } } } public static void main(String[] args) { UndirectedGraph graph = new UndirectedGraph("graph.txt"); System.out.println(graph); UndirectedGraphDFSCC graphDFS = new UndirectedGraphDFSCC(graph); System.out.println(graphDFS.getCcCount()); } }
可是咱們想知道的不單單是一個圖有多少連通份量,而是每一個連通份量都有哪些頂點
咱們能夠改變一下visited數組,改成int數組,若是數組裏的值是-1,表明此下標表明的頂點未訪問過,若是數組裏的值是0,表明此下標表明的頂點是屬於第一個連通份量的,若是數組裏的值是1,表明此下標表明的頂點是屬於第二個連通份量的,以此類推,有以下代碼app
public class UndirectedGraphCC { private UndirectedGraph graph; private int[] visited; private int ccCount;//連通份量 public UndirectedGraphCC(UndirectedGraph graph){ this.graph = graph; visited = new int[graph.vertexNum()]; for(int i=0;i<visited.length;i++){ //visited裏面-1表示沒有訪問,0表示第一個聯通份量,1表示第二個連通份量,以此類推 visited[i] = -1; } for(int v=0;v<graph.vertexNum();v++){ if(visited[v]==-1){ dfs(v,ccCount); ccCount++; } } } private void dfs(int v,int ccId){ visited[v] = ccId; for(int w:graph.adj(v)) { if(visited[w]==-1){ dfs(w,ccId); } } } /** * 返回全部的連通份量 * @return */ public List<Integer>[] components(){ List<Integer>[] res = new ArrayList[ccCount]; for(int i=0;i<ccCount;i++){ res[i] = new ArrayList<>(); } for(int v=0;v<graph.vertexNum();v++){ res[visited[v]].add(v); } return res; } public boolean isConnected(int v,int w){ graph.validateVertex(v); graph.validateVertex(w); return visited[v]==visited[w]; } public int getCcCount(){return ccCount;} @Override public String toString() { StringBuilder sb = new StringBuilder(); for(int v:visited){ sb.append(v+" "); } sb.append("\n連通份量:"+ccCount); int index = 1; for (List<Integer> list:components()){ sb.append("\n第"+index+++"個連通份量的頂點:"); for (int v:list) { sb.append(v+" "); } } return sb.toString(); } public static void main(String[] args) { UndirectedGraph graph = new UndirectedGraph("graph.txt"); System.out.println(graph); UndirectedGraphCC graphCC = new UndirectedGraphCC(graph); System.out.println(graphCC); System.out.println(graphCC.isConnected(0, 6)); System.out.println(graphCC.isConnected(0, 5)); } }
public class UndirectedGraphCCBFS { private UndirectedGraph graph; private int[] visited; private int ccCount; public UndirectedGraphCCBFS(UndirectedGraph graph){ this.graph = graph; visited = new int[graph.vertexNum()]; for(int i=0;i<visited.length;i++){ //visited裏面-1表示沒有訪問,0表示第一個聯通份量,1表示第二個連通份量,以此類推 visited[i] = -1; } //多個聯通份量必須for for(int v=0;v<graph.vertexNum();v++){ if(visited[v]==-1){ bfs(v,ccCount); ccCount++; } } } private void bfs(int v,int ccId){ Queue<Integer> queue = new LinkedList(); queue.offer(v); visited[v] = ccId; while(!queue.isEmpty()){ int w = queue.poll(); for(int u:graph.adj(w)){ if(visited[u]==-1){ visited[u] = ccId; queue.offer(u); } } } } /** * 返回全部的連通份量 * @return */ public List<Integer>[] components(){ List<Integer>[] res = new ArrayList[ccCount]; for(int i=0;i<ccCount;i++){ res[i] = new ArrayList<>(); } for(int v=0;v<graph.vertexNum();v++){ res[visited[v]].add(v); } return res; } public boolean isConnected(int v,int w){ graph.validateVertex(v); graph.validateVertex(w); return visited[v]==visited[w]; } public int getCcCount() { return ccCount; } @Override public String toString() { StringBuilder sb = new StringBuilder(); for(int v:visited){ sb.append(v+" "); } sb.append("\n連通份量:"+ccCount); int index = 1; for (List<Integer> list:components()){ sb.append("\n第"+index+++"個連通份量的頂點:"); for (int v:list) { sb.append(v+" "); } } return sb.toString(); } public static void main(String[] args) { UndirectedGraph graph = new UndirectedGraph("graph.txt"); System.out.println(graph); UndirectedGraphCCBFS graphBFS = new UndirectedGraphCCBFS(graph); System.out.println(graphBFS); } }
7 6 0 1 0 2 1 3 2 6 2 3 1 4
public class UndirectedGraph { private int V;//頂點數 private int E;//邊數 private TreeSet<Integer>[] adj;//鄰接表,TreeSet數組存儲 public UndirectedGraph(String filename){ File file = new File(filename); try(Scanner scanner = new Scanner(file)){ V = scanner.nextInt();//頂點數 if(V<=0) throw new RuntimeException("頂點個數必須大於0"); adj = new TreeSet[V]; for(int i=0;i<V;i++){ adj[i] = new TreeSet<>(); } E = scanner.nextInt();//邊數 if(E<0) throw new RuntimeException("邊數不能爲負數"); for(int i=0;i<E;i++){ int a = scanner.nextInt(); validateVertex(a); int b = scanner.nextInt(); validateVertex(b); //自環邊檢測 if(a==b){ throw new RuntimeException("簡單圖不能包含自環邊"); } //平行邊檢測 if(adj[a].contains(b)){ throw new RuntimeException("簡單圖不能包含平行邊"); } adj[a].add(b); adj[b].add(a); } }catch (IOException e){ e.printStackTrace(); } } public void validateVertex(int v){ if(v<0||v>=V){ throw new RuntimeException("頂點下標溢出"); } } public int vertexNum(){ return V; } public int edgeNum(){ return E; } public boolean hasEdge(int v,int w){ validateVertex(v); validateVertex(w); return adj[v].contains(w); } //鄰接頂點 public Iterable<Integer> adj(int v){ validateVertex(v); return adj[v]; } //度 public int degree(int v){ validateVertex(v); return adj[v].size(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(String.format("V = %d,E = %d\n",V,E)); for(int i=0;i<adj.length;i++){ sb.append(i+":"); for (Iterator<Integer> it = adj[i].iterator(); it.hasNext(); ) { sb.append(it.next()+" "); } sb.append("\n"); } return sb.toString(); } public static void main(String[] args) { UndirectedGraph graph = new UndirectedGraph("graph.txt"); System.out.println(graph); }