不連通的邊的權值為無限大的值,為一個定義好的最大值(因為要找最小的路徑,權值為無限大不會被訪問)
從起點出發,標志該起點為遍歷過的,記錄到每個點的路徑值(遍歷過的就不算)。直到所有的點都被作為了起點(遍歷了)
數據結構:頂點,有向邊,圖
算法:初始化最小路徑數組的值
循環{
從最小路徑數組中獲取當前頂點有向邊的最小值的那個點和那個權值
獲取當前點,當前邊的值
更新當前點
更新最小路徑(算法核心)
}
//有向邊 public class DistPar { public int distance;//權值 public int parentVert;//父頂點 public DistPar(int pv,int d) { distance=d; parentVert=pv; } }
//圖的頂點 public class Vertex { public char label;//頂點的標識符 public boolean isVisited;//頂點有無被訪問的標志 public Vertex(char lab) {//初始化頂點(屬性) label=lab; isVisited=false; } }
public class Graph { private final int MAX_VERTS=20;//最大頂點數 private final int INFINITY=1000000;//無限大的值,用於表示不連通的權值 private Vertex[] vertexList;//頂點數組 private int [][]adjMat;//頂點關系的領接矩陣(鄰接矩陣的每行或者每列的位置跟頂點數組是對應的) private int nVerts;//當前頂點個數 private int nTree;//記錄當前訪問的頂點數量,控制循環 private DistPar [] sPath;//保存路徑(即保存有向邊的數組) private int currentnVert;//標志訪問的當前頂點,該值為當前頂點索引值 private int startToCurrent;//標志到currentnVert點的邊的權值 public Graph() {//初始化圖 vertexList=new Vertex[MAX_VERTS]; //初始化頂點數組 adjMat=new int [MAX_VERTS][MAX_VERTS] ;//初始化鄰接矩陣 for(int j=0;j<MAX_VERTS;j++) for(int i=0;i<MAX_VERTS;i++) adjMat[j][i]=INFINITY; nVerts=0;//初始化當前頂點個數 nTree=0; sPath=new DistPar[MAX_VERTS]; } //向頂點數組中添加頂點對象(lab為頂點對象的label屬性值) public void addVertex(char lab) { vertexList[nVerts++]=new Vertex(lab);//建立lab對象,往數組內添加 } //添加邊(向鄰接矩陣中改變權值) public void addEdge(int start,int end,int weight) { //因為是有向圖 adjMat[start][end]=weight; } //最短路徑計算 public void path() { int startTree=0;//起始頂點為0 vertexList[startTree].isVisited=true; nTree=1; for(int j=0;j<nVerts;j++) {//訪問當前頂點的鄰接點 int tempDist=adjMat[startTree][j];//獲取邊的權值 sPath[j]=new DistPar(startTree,tempDist); //將有向邊的存入數組中.起始點是startTree,權值是tempDist,放入數組的索引為j的位置 }//初始化sPath數組 //不斷循環改變sPath數組的值 //找最短路徑 //獲取當前點之前需要比較,獲取邊權值最小的那個點 while(nTree<nVerts) {//需要遍歷nVerts次,當nTree為0時,訪問了一個頂點,當訪問nVerts個時,nTree為nVerts-1 int indexMin=getMin();//在sPath(有向邊數組)中獲取權值最小的到達點 int minDist=sPath[indexMin].distance;//獲取有向邊的權值 if(minDist==INFINITY) {//因為如果在sPath數組中獲取的最小的邊值是無窮大,說明該圖是不通的 System.out.println("不通"); break; }else { currentnVert=indexMin;//將該點又作為源點開始循環 startToCurrent=sPath[indexMin].distance;//有向邊數組中的值是總距離 } vertexList[currentnVert].isVisited=true; nTree++; //更新最小路徑數組(如果當前點的startToCurrent加上當前點到其他點的值小,就需要更新) adj_sPath(); } displayPath(); nTree=0; for(int j=0;j<nVerts;j++) vertexList[j].isVisited=false; } public void adj_sPath() { int column=1; while(column<nVerts) {//更新除了遍歷過的頂點 if(vertexList[column].isVisited) { column++; continue; }//遍歷過的頂點就不更新這條記錄 int currentToFringe=adjMat[currentnVert][column];//終點是column int startToFringe=startToCurrent+currentToFringe;//startToCurrent為currentnVert點之前的距離 int sPathDist=sPath[column].distance; if(startToFringe<sPathDist) {//更新 sPath[column].parentVert=currentnVert; sPath[column].distance=startToFringe; } column++; } } //找到一個當前頂點的聯通的點,而且是權值最小的邊 public int getMin() { int minDist=INFINITY;//記錄獲取到的頂點的索引 int indexMin=0;//記錄獲取到的索引值 for(int j=1;j<nVerts;j++) {//在數組中找某個頂點 if(!vertexList[j].isVisited && sPath[j].distance<minDist) {//該頂點是沒有被訪問過的,而且權值是比minDist更小的 minDist=sPath[j].distance;//獲取該值 indexMin=j;//獲取該點的索引 } } return indexMin; } public void displayPath() { for(int j=0;j<nVerts;j++) {//遍歷, System.out.print(vertexList[j].label+"=");//頂點標記 if(sPath[j].distance==INFINITY) {//查詢頂點是否在sPath有邊 System.out.print("沒有"); }else { System.out.print(sPath[j].distance);//有的話就輸出 } char parent=vertexList[sPath[j].parentVert].label;//查詢該頂點的父頂點 System.out.println("("+parent+")"); } System.out.println(); } }
public class Test { public static void main(String[] agrs) { Graph theGraph=new Graph();//創建一個圖 theGraph.addVertex('A');//添加頂點 theGraph.addVertex('B');//添加頂點 theGraph.addVertex('C');//添加頂點 theGraph.addVertex('D');//添加頂點 theGraph.addVertex('E');//添加頂點 theGraph.addEdge(0,1,50);//添加邊 theGraph.addEdge(0,3,80);//添加邊 theGraph.addEdge(1,2,60);//添加邊 theGraph.addEdge(1,3,90);//添加邊 theGraph.addEdge(2,4,40);//添加邊 theGraph.addEdge(3,2,20);//添加邊 theGraph.addEdge(3,4,70);//添加邊 theGraph.addEdge(4,1,50);//添加邊 theGraph.path(); } }