/** * 文件名:AdjacencyMatrix.java * 所在包:Graph * 日期:2013-12-31 上午9:27:47 * 版本信息:version V1.0 * Copyright Corporation 2013 * 版權全部: * */ package Graph; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Scanner; /** * * 項目名稱:jobdu * 類名稱:AdjacencyMatrix * 類描述:鄰接矩陣 = 順序表(存儲頂點信息) + 二維數組(表示頂點之間的鄰接關係) * 建立人:黃傳聰 * 建立時間:2013-12-31 上午9:27:47 * 修改人: * 修改時間: * 修改備註: * @version */ public class AdjacencyMatrix { /** 頂點數量 */ private int n; /** 頂點數組 */ private int[] vertexes; /** 二維數組,表示頂點之間的鄰接關係 0表示無關係 */ private int[][] matrix; /** 是不是無向圖:true ;有向圖:false */ private boolean flag ; //各個節點的父節點 private int[] fathers ; public AdjacencyMatrix() { //默認爲10 this(10,true); } public AdjacencyMatrix(int n, boolean flag) { this.n = n; this.flag = flag; vertexes = new int[n]; matrix = new int[n][n]; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ matrix[i][j] = Integer.MAX_VALUE; } } fathers = new int[n]; } /** * 方法名稱:init() * 方法描述:開始填充矩陣 * @param * @return String * @Exception */ public void init(){ int head , tail, w = 0; Scanner scanner = new Scanner(System.in); System.out.println("請輸入 邊的起始和終止頂點序號 和 邊的權值: ************"); while(scanner.hasNext()){ head = scanner.nextInt(); tail = scanner.nextInt(); w = scanner.nextInt(); if(head==0 && tail==0 && w == 0){ System.out.println("********輸入完畢********************"); break; } matrix[head-1][tail-1] = w; if(flag){ matrix[tail-1][head-1] = w; } } for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ System.out.print(matrix[i][j] + " "); } System.out.println(); } } public int[][] getMatrix() { return matrix; } public void setMatrix(int[][] matrix) { this.matrix = matrix; } public int[] getVertexes() { return vertexes; } public void setVertexes(int[] vertexes) { this.vertexes = vertexes; } /** * 方法名稱:main() * 方法描述: * @param * @return String * @Exception */ public static void main(String[] args) { // TODO Auto-generated method stub int n = 6; //使用鄰接矩陣存儲一個無向圖 AdjacencyMatrix adjacencyMatrix = new AdjacencyMatrix(n,true); Scanner scanner = new Scanner(System.in); int[] vertexes = new int[n]; System.out.println("請輸入頂點節點: "); for(int i=0;i<n;i++){ vertexes[i] = scanner.nextInt(); } adjacencyMatrix.setVertexes(vertexes); adjacencyMatrix.init(); /*for(int i=0;i<adjacencyMatrix.n;i++){ for(int j=0;j<adjacencyMatrix.n;j++){ System.out.print(adjacencyMatrix.getMatrix()[i][j] + " "); } System.out.println(); } int[] result = adjacencyMatrix.prim(2); for(int a : result){ System.out.print((a+1) + " -> "); }*/ adjacencyMatrix.kruscal(); } /** * 方法名稱:prim() * 方法描述:最小生成樹,prim 算法實現:對頂點進行遍歷,適用於稠密圖,時間複雜度o(n*n) * @param begin: 開始遍歷的節點 * 測試數據: * 1 2 3 4 5 6 1 2 6 1 3 1 1 4 5 2 5 3 2 3 5 3 4 5 3 5 6 3 6 4 4 6 2 5 6 6 0 0 0 * @return String * @Exception */ public int[] prim(int begin){ int index = 0; //結果 int[] result = new int[n]; /*兩個頂點之間的最小距離*/ int[] lowCost = new int[n]; /*記錄頂點是否被選中, 默認爲未選中*/ int[] closet = new int[n]; //標記節點選中 closet[begin] = 1; result[index++] = begin; for(int i=0;i<n;i++){ lowCost[i] = matrix[begin][i]; } //從餘下的n-1的節點中查找節點 for(int j=1;j<n;j++){ //從0-i中選出一個路徑最小的節點,加入到選中節點中 int min = Integer.MAX_VALUE; int k = 0; //記錄最小值得位置 for(int i=0;i<n;i++){ if(lowCost[i]<min && closet[i] == 0 && lowCost[i] != 0){ min = lowCost[i]; k = i; } } //選中節點 closet[k] = 1; lowCost[k] = 0; result[index++] = k; //修改lowCost中的值 for(int l=0;l<n;l++){ if(closet[l]==0 && lowCost[l] > matrix[k][l]&& lowCost[l] != 0){ lowCost[l] = matrix[k][l]; } } } return result; } public void prim(){ int[] lowCost = new int[n]; int[] closeSet = new int[n]; int i ,j, k, min; for(i=1;i<n;i++){ lowCost[i] = matrix[0][i]; closeSet[i] = 1; } for(i=1;i<n;i++){ min = Integer.MAX_VALUE; k = 0; for(j=1;j<n;j++){ if(lowCost[j]<min && lowCost[j] != 0){ min = lowCost[j];k = j; } } lowCost[k] = 0; System.out.println(closeSet[k]); closeSet[k] = 0; for(j=1;j<n;j++){ if(matrix[k][j]<lowCost[j] && matrix[k][j] != 0){ lowCost[j] = matrix[k][j]; closeSet[j] = k; } } } // for(int out : closeSet){ // System.out.println(out); // } } /** * 方法名稱:kruscal() * 方法描述:kruscal算法,能夠使用並查集進行操做 * @param * @return String * @Exception */ public void kruscal(){ final class Edge{ //設置邊的兩個頂點和權值 private int from; private int end; private int weight; public Edge(){} public Edge(int from, int end, int weight){ this.from = from; this.end = end; this.weight = weight; } } //初始化其父節點爲其自己 //頂點數組中存放的數據爲 1, 2 ,3 。。 //因 而在使用時,須要減一 for(int i=0;i<n;i++){ fathers[vertexes[i]-1] = vertexes[i] - 1; } List<Edge> edges = new ArrayList<Edge>(); //構建list //若是是無向圖,只需構建一側 //無向圖 Edge edge = null; if(flag){ for(int i=0;i<n;i++){ for(int j=0;j<=i;j++){ if(matrix[i][j] != Integer.MAX_VALUE && matrix[i][j] != 0){ edge = new Edge(i, j, matrix[i][j]); edges.add(edge); } } } }else{ for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(matrix[i][j] != Integer.MAX_VALUE && matrix[i][j] != 0){ edge = new Edge(i, j, matrix[i][j]); edges.add(edge); } } } } //對edges按照權值排序 Collections.sort(edges, new Comparator<Edge>() { @Override public int compare(Edge e1, Edge e2) { // TODO Auto-generated method stub if(e1.weight - e2.weight > 0){ return 1; }else if(e1.weight - e2.weight < 0){ return -1; }else{ return 0; } } }); //對每條邊的兩個頂點設置父頂點 for(Edge e : edges){ int a = getFather(e.from); int b = getFather(e.end); if(a != b){ fathers[b] = a; System.out.println((e.from+1) + " -> " + (1+e.end)); } } } private int getFather(int x){ return (x == fathers[x]) ? x : (fathers[x]=getFather(fathers[x])); } }