數據結構-圖-Java實現:有向圖 圖存儲(鄰接矩陣),最小生成樹,廣度深度遍歷,圖的連通性,最短路徑1


  • import java.util.ArrayList;  
  •   
  • import java.util.List;  
  •   
  •    
  •   
  • // 模塊E  
  •   
  • public class AdjMatrixGraph<E> {  
  •   
  • protected SeqList<E> vertexlist; // 順序表存儲圖的頂點集合  
  •   
  •    
  •   
  • protected int[][] adjmatrix; // 圖的鄰接矩陣 二維圖 存儲的是每個頂點的名稱(A,B,C,D....)  
  •   
  •    
  •   
  • private final int MAX_WEIGHT = Integer.MAX_VALUE / 2;  
  •   
  •    
  •   
  • // private final int MAX_WEIGHT = 10000;  
  •   
  •    
  •   
  • // -------一,構造圖:增刪改查-------------------------//  
  •   
  • public AdjMatrixGraph(int n) {// n為頂點的數目  
  •   
  • this.vertexlist = new SeqList<E>(n);  
  •   
  • this.adjmatrix = new int[n][n];  
  •   
  • for (int i = 0; i < n; i++)  
  •   
  • for (int j = 0; j < n; j++)  
  •   
  • this.adjmatrix[i][j] = (i == j) ? 0 : MAX_WEIGHT;  
  •   
  • // 對角線上為0,其他的都為無窮大。  
  •   
  • }  
  •   
  •    
  •   
  • // 構造函數內一個是字符串數組,一個是edge的set集合  
  •   
  • public AdjMatrixGraph(E[] vertices, Edge[] edges) {  
  •   
  • this(vertices.length);  
  •   
  • for (int i = 0; i < vertices.length; i++)  
  •   
  • insertVertex(vertices[i]);// 添加頂點  
  •   
  • for (int j = 0; j < edges.length; j++)  
  •   
  • insertEdge(edges[j]);// 添加邊  
  •   
  • }  
  •   
  •    
  •   
  • // 構造函數內一個是數組集合,一個是edge的set集合  
  •   
  • public AdjMatrixGraph(SeqList<E> list, Edge[] edges) {  
  •   
  • this(list.length());  
  •   
  • this.vertexlist = list;  
  •   
  • for (int j = 0; j < edges.length; j++)  
  •   
  • insertEdge(edges[j]);  
  •   
  • }  
  •   
  •    
  •   
  • // 顯示出一共頂點的數目  
  •   
  • public int vertexCount() {  
  •   
  • return this.vertexlist.length();  
  •   
  • }  
  •   
  •    
  •   
  • // 根據編號得到該頂點  
  •   
  • public E get(int i) {  
  •   
  • return this.vertexlist.get(i);  
  •   
  • }  
  •   
  •    
  •   
  • public boolean insertVertex(E vertex) { // 插入一個頂點,若插入成功,返回true  
  •   
  •    
  •   
  • return this.vertexlist.add(vertex);  
  •   
  • }  
  •   
  •    
  •   
  • public boolean insertEdge(int i, int j, int weight)  
  •   
  • // 插入一條權值為weight的邊<vi,vj>,若該邊已有,則不插入  
  •   
  • {  
  •   
  • if (i >= 0 && i < vertexCount() && j >= 0 && j < vertexCount()  
  •   
  • && i != j && adjmatrix[i][j] == MAX_WEIGHT) {  
  •   
  • // 先判斷該邊兩個頂點的編號是否在范圍,該邊的值是否為最大值,來確定所添加邊的值是否存在;  
  •   
  • this.adjmatrix[i][j] = weight;// 添加權值  
  •   
  • return true;  
  •   
  • }  
  •   
  • return false;  
  •   
  • }  
  •   
  •    
  •   
  • public boolean insertEdge(Edge edge) {  
  •   
  • if (edge != null)  
  •   
  • ;  
  •   
  • return insertEdge(edge.start, edge.dest, edge.weight);  
  •   
  • }  
  •   
  •    
  •   
  • public String toString() {  
  •   
  • String str = "頂點集合: " + vertexlist.toString() + "\n";  
  •   
  • str += "鄰近矩陣:    \n";  
  •   
  • int n = vertexCount();  
  •   
  • for (int i = 0; i < n; i++) {  
  •   
  • for (int j = 0; j < n; j++) {  
  •   
  • if (adjmatrix[i][j] == MAX_WEIGHT)  
  •   
  • str += " ∞";// 最大值(不存在)的時候的顯示方式;  
  •   
  • else  
  •   
  • str += " " + adjmatrix[i][j];// 每一個頂點到其他頂點的權值  
  •   
  • }  
  •   
  • str += "\n";  
  •   
  • }  
  •   
  • return str;  
  •   
  • }  
  •   
  •    
  •   
  • public boolean removeEdge(int i, int j) // 刪除邊〈vi,vj〉,若成功,返回T  
  •   
  • {  
  •   
  • if (i >= 0 && i < vertexCount() && j >= 0 && j < vertexCount()  
  •   
  • && i != j && this.adjmatrix[i][j] != MAX_WEIGHT) {  
  •   
  • // 判斷該邊的兩個頂點是否存在,以及改邊的值是否為最大值來判斷改邊是否存在;  
  •   
  • this.adjmatrix[i][j] = MAX_WEIGHT; // 設置該邊的權值為無窮大,說明已不存在;  
  •   
  • return true;  
  •   
  • }  
  •   
  • return false;  
  •   
  • }  
  •   
  •    
  •   
  • public boolean removeVertex(int v) // 刪除序號為v的頂點及其關聯的邊  
  •   
  • {  
  •   
  • int n = vertexCount(); // 刪除之前的頂點數  
  •   
  • if (v >= 0 && v < n) {// V的要求范圍  
  •   
  • this.vertexlist.remove(v); // 刪除順序表的第i個元素,頂點數已減一  
  •   
  • for (int i = v; i < n - 1; i++)  
  •   
  • for (int j = 0; j < n; j++)  
  •   
  • this.adjmatrix[i][j] = this.adjmatrix[i + 1][j]; // 鄰接矩陣:刪除點以下往上移動一位  
  •   
  • for (int j = v; j < n - 1; j++)  
  •   
  • for (int i = 0; i < n - 1; i++)  
  •   
  • this.adjmatrix[i][j] = this.adjmatrix[i][j + 1]; // 鄰接矩陣:刪除點以右往左移動一位  
  •   
  • return true;  
  •   
  • }  
  •   
  • return false;  
  •   
  • }  
  •   
  •    
  •   
  • public int getFirstNeighbor(int v) // 返回頂點v的第一個鄰接頂點的序號  
  •   
  • {  
  •   
  • return getNextNeighbor(v, -1);  
  •   
  • // 若不存在第一個鄰接頂點,則返回-1  
  •   
  •    
  •   
  • public int getNextNeighbor(int v, int w) { // 返回v在w后的下一個鄰接頂點  
  •   
  • if (v >= 0 && v < vertexCount() && w >= -1 && w < vertexCount()// 對v  
  •   
  • // w的范圍限定  
  •   
  • && v != w)  
  •   
  • for (int j = w + 1; j < vertexCount(); j++)  
  •   
  • // w=-1時,j從0開始尋找下一個鄰接頂點  
  •   
  • if (adjmatrix[v][j] > 0 && adjmatrix[v][j] < MAX_WEIGHT)  
  •   
  • // 遍歷和v相關的點,得到下一個點  
  •   
  • return j;  
  •   
  • return -1;  
  •   
  • }  
  •   
  •    
  •   
  • // -------二,最小生成樹-------------------------//  
  •   
  •    
  •   
  • /* 
  •  
  • * 普里姆算法的基本思想: 取圖中任意一個頂點 v 作為生成樹的根,之后往生成樹上添加新的頂點 w。 在添加的頂點 w 
  •  
  • * 和已經在生成樹上的頂點v之間必定存在一條邊, 並且該邊的權值在所有連通頂點 v 和 w 之間的邊中取值最小。 
  •  
  • * 之后繼續往生成樹上添加頂點,直至生成樹上含有 n-1 個頂點為止。 
  •  
  • */  
  •   
  •    
  •   
  • public AdjMatrixGraph minSpanTree_prim() {  
  •   
  • Edge[] mst = new Edge[this.vertexCount() - 1]; // n個頂點最小生成樹有n-1條邊  
  •   
  • int un;  
  •   
  • List<Integer> u = new ArrayList<Integer>();// 存放所有已訪問過的頂點集合  
  •   
  • u.add(0);// 起始點默認為標識為0的頂點  
  •   
  • for (int i = 0; i < this.vertexCount() - 1; i++) {  
  •   
  • int minweight = MAX_WEIGHT;// 最小邊的時候,權值  
  •   
  • int minstart = MAX_WEIGHT;// 最小邊的時候,起點  
  •   
  • int mindest = MAX_WEIGHT;// 最小邊的時候,終點  
  •   
  • for (int j = 0; j < u.size(); j++) {  
  •   
  • un = u.get(j);  
  •   
  • for (int k = 0; k < this.vertexCount(); k++) {  
  •   
  • // 獲取最小值的條件:1.該邊比當前情況下的最小值小;2.該邊還未訪問過;  
  •   
  • if ((minweight > adjmatrix[un][k]) && (!u.contains(k))) {  
  •   
  • minweight = adjmatrix[un][k];  
  •   
  • minstart = un;  
  •   
  • mindest = k;  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • System.out.println("一次遍歷所添加的最小邊:他的權值,起點,終點分別為:weight:" + minweight  
  •   
  • "start:" + minstart + "dest:" + mindest);  
  •   
  • u.add(mindest);  
  •   
  • Edge e = new Edge(minstart, mindest, adjmatrix[minstart][mindest]);  
  •   
  • mst[i] = e;  
  •   
  • }  
  •   
  • return new AdjMatrixGraph(this.vertexlist, mst); // 構造最小生成樹相應的圖對象  
  •   
  • }  
  •   
  •    
  •   
  • /* 
  •  
  • * public AdjMatrixGraph minSpanTree_kruskal() { } 
  •  
  • */  
  •   
  •    
  •   
  • // -------三,圖的遍歷(廣度遍歷,深度遍歷)-------------------------//  
  •   
  • public void DFStraverse() {  
  •   
  • int n = this.vertexCount();  
  •   
  • boolean[] visited = new boolean[n];  
  •   
  • for (int i = 1; i < n; i++) {  
  •   
  • visited[i] = false;  
  •   
  • }  
  •   
  • // 編號0為起始點,進行一次深度優先遍歷(一次得到一個連通分量)  
  •   
  • for (int j = 0; j < n; j++) {  
  •   
  • if (!visited[j]) {  
  •   
  • System.out.println("以該頂點為" + j + "起始點的遍歷:");  
  •   
  • this.DFS(j, visited);  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  •    
  •   
  • // 參數1:遍歷起始點的編號,參數2:記錄各個頂點是否被訪問過  
  •   
  • public void DFS(int v, boolean[] visited2) {  
  •   
  • boolean[] visited = visited2;  
  •   
  • visited[v] = true;  
  •   
  • System.out.println("遍歷頂點" + v);  
  •   
  • for (int w = this.getFirstNeighbor(v); w >= 0; w = this  
  •   
  • .getNextNeighbor(v, w)) {  
  •   
  • if (!visited[w]) {  
  •   
  • visited[w] = true;  
  •   
  • DFS(w, visited);  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  •    
  •   
  • public void BFStraverse() {  
  •   
  • int n = this.vertexCount();  
  •   
  • boolean[] visited = new boolean[n];  
  •   
  • MyQueue myqueue = new MyQueue();  
  •   
  • for (int i = 1; i < n; i++) {  
  •   
  • visited[i] = false;  
  •   
  • }  
  •   
  •    
  •   
  • for (int j = 0; j < n; j++) {  
  •   
  • if (!visited[j]) {  
  •   
  • visited[j] = true;  
  •   
  • System.out.println("遍歷起點:" + j);  
  •   
  • myqueue.EnQueue(j);  
  •   
  • while (!myqueue.empty()) {  
  •   
  • int v = (Integer) myqueue.DeQueue();  
  •   
  • System.out.println("遍歷點:" + v);  
  •   
  • for (int w = this.getFirstNeighbor(v); w >= 0; w = this  
  •   
  • .getNextNeighbor(v, w)) {  
  •   
  • if (!visited[w]) {  
  •   
  • visited[w] = true;  
  •   
  • myqueue.EnQueue(w);  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  •    
  •   
  • }  
  •   
  •    
  •   
  • // -------四,圖的最短路徑Dijkstra算法-------------------------//  
  •   
  • public void Dijkstra() {  
  •   
  • int n = this.vertexCount();  
  •   
  • int minweight = MAX_WEIGHT;  
  •   
  • int minUn = 0;  
  •   
  • int[] minmatrix = new int[n];// 存放當前起始點到其余各個頂點的距離;  
  •   
  • boolean[] isS = new boolean[n];// 判斷各個是否被訪問過  
  •   
  • String[] route = new String[n];// 每個字符串是顯示對應頂點最短距離的路徑;  
  •   
  • for (int i = 1; i < n; i++) {// 初始化  
  •   
  • minmatrix[i] = adjmatrix[0][i];  
  •   
  • isS[i] = false;  
  •   
  • route[i] = "起點->" + i;  
  •   
  • }  
  •   
  • for (int i = 1; i < n; i++) {  
  •   
  • // 選擇 當前 和起點 連通的,且值最小的頂點;  
  •   
  • for (int k = 1; k < n; k++) {  
  •   
  • if (!isS[k]) {  
  •   
  • if (minmatrix[k] < minweight) {  
  •   
  • minweight = minmatrix[k];  
  •   
  • minUn = k;  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • isS[minUn] = true;// 將該點設置為已訪問;  
  •   
  • for (int j = 1; j < n; j++) {  
  •   
  • if (!isS[j]) {// 判斷:該頂點還沒加入到S中/屬於U-S;  
  •   
  • if (minweight + adjmatrix[minUn][j] < minmatrix[j]) {  
  •   
  • // 通過當下最小值 訪問到得其他頂點的距離小於原先的最小值 則進行交換值  
  •   
  • minmatrix[j] = minweight + adjmatrix[minUn][j];  
  •   
  • route[j] = route[minUn] + "->" + j;  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • minweight = MAX_WEIGHT;// 因為要放到下一個循環中,所以一定要重設置一下,回到最大值  
  •   
  • }  
  •   
  • for (int m = 1; m < n; m++) {  
  •   
  • System.out.println("從V0出發到達" + m + "點");  
  •   
  • if (minmatrix[m] == MAX_WEIGHT) {  
  •   
  • System.out.println("沒有到達該點的路徑");  
  •   
  • else {  
  •   
  • System.out.println("當前從V0出發到達該點的最短距離:" + minmatrix[m]);  
  •   
  • System.out.println("當前從V0出發到達該點的最短距離:" + route[m]);  
  •   
  •    
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  •    
  •   
  • // -------五,圖的連通性-------------------------//  
  •   
  • public boolean isConnect() {  
  •   
  • int n = this.vertexCount();  
  •   
  • boolean[] visited = new boolean[n];  
  •   
  • // 記錄不能一次深度優先遍歷通過的數目  
  •   
  • // 全部頂點作為出發點開始遍歷,如果全部都不能一次遍歷通過(notConnectNum == n),說明該圖不連通。  
  •   
  • int notConnectNum = 0;  
  •   
  • for (int j = 0; j < n; j++) {  
  •   
  • for (int i = 0; i < n; i++) {  
  •   
  • visited[i] = false;  
  •   
  • }  
  •   
  • this.DFS(j, visited);  
  •   
  • for (int k = 0; k < n; k++) {  
  •   
  • System.out.println(visited[k]);  
  •   
  • if (visited[k] == false) {  
  •   
  • notConnectNum++;  
  •   
  • break;// 一旦有沒有被遍歷到的頂點(說明該頂點不屬於該連通分量),跳出循環  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • if (notConnectNum == n) {  
  •   
  • System.out.println("此圖是不連通的");  
  •   
  • return false;  
  •   
  • else {  
  •   
  • System.out.println("此圖是連通的");  
  •   
  • return true;  
  •   
  • }  
  •   
  • }  
  •   
  •    
  •   
  • // -------六,圖的拓撲排序-------------------------//  
  •   
  • public void topologicalSort() {  
  •   
  • int n = this.vertexCount();  
  •   
  • int[] indegree = new int[n];  
  •   
  • MyStack mystack = new MyStack();  
  •   
  • String route = "拓撲排序出發:";  
  •   
  • int count = 0;  
  •   
  • for (int i = 0; i < n; i++) {  
  •   
  • indegree[i] = 0;  
  •   
  • for (int j = 0; j < n; j++) {//獲取每一個頂點的入度  
  •   
  • if (adjmatrix[j][i] != 0 && adjmatrix[j][i] != MAX_WEIGHT) {  
  •   
  • indegree[i] += 1;  
  •   
  • }  
  •   
  • }//先將入度為0的頂點加入到棧中  
  •   
  • if (indegree[i] == 0) {  
  •   
  • mystack.push(i);  
  •   
  • }  
  •   
  • }  
  •   
  • while (!mystack.empty()) {  
  •   
  • int v = (Integer) mystack.pop();//從棧中刪除該頂點  
  •   
  • route += "->" + v;  
  •   
  • ++count;  
  •   
  • for (int w = this.getFirstNeighbor(v); w >= 0; w = this  
  •   
  • .getNextNeighbor(v, w)) {  
  •   
  • indegree[w] -= 1;//因為該頂點被“刪除”,所有以該頂點為弧尾的邊的弧頭的入度減一  
  •   
  • if (indegree[w] == 0) {  
  •   
  • mystack.push(w);//先將入度為0的頂點加入到棧中  
  •   
  • }  
  •   
  • }  
  •   
  • }  
  •   
  • if (count < n) {//當經歷拓撲排序遍歷后,所有頂點都被“刪除”時(count=n),此時實現拓撲排序  
  •   
  • System.out.println("存在回路,不滿足拓撲排序的條件");  
  •   
  • else {  
  •   
  • System.out.println("實現拓撲排序" + route);  
  •   
  •    
  •   
  • }  
  •   
  • }  
  •   
  •   
  • }  

  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM