1. 程式人生 > >最短路徑(鄰接矩陣)-Dijkstra演算法

最短路徑(鄰接矩陣)-Dijkstra演算法

   Dijkstra演算法又叫作迪傑斯特拉演算法,是利用"貪心法"(在對問題進行求解時,總是做出在當前看來最好的選擇策略)設計演算法的一個成功範例。

        適用條件:帶權無環和無負權值

舉個栗子:

  

 

   Dijkstra演算法的程式碼實現如下:

package com.threeTop.www;

import java.util.Stack;

/**
 * 鄰接矩陣儲存方式的Dijkstra演算法
 * @author wjgs
 *
 */
public class Dijkstra {
	
	    //通過下標對映元素值
		private int[] mapping;
		
		//圖的二維陣列
		private int[][] matrix;
		
		/**
		 * 初始化圖的頂點
		 * @param vertexes 頂點陣列
		 */
		 public Dijkstra(int []vertexes)
		 {
			 
			 int length=vertexes.length;
			 mapping=new int[length];
			 matrix=new int[length][length]; //圖的二維矩陣
			 for(int i=0;i<length;i++)
			 {
				mapping[i]=vertexes[i];
				 
			 }
			 
			 
			 
		 }
		 
		 /**
		  * 新增具有權值的邊
		  * @param start
		  * @param end
		  * @param value
		  */
		 public void addEdge(int start,int end,int value)
		 {
			 int x=-1;
			 int y=-1;
			 
			 //尋找座標
			 for(int i=0;i<mapping.length;i++)
			 {
				 if(x!=-1&&y!=-1)
				 {
					 break;
				 }
				 if(start==mapping[i])
				 {
					 x=i;
				 }
				 if(end==mapping[i])
				 {
					 y=i;
				 }
			 }
			 
			 //判斷頂點是否存在
			 if(x==-1||y==-1||x>mapping.length-1||y>mapping.length-1)
			 {
				 throw new IndexOutOfBoundsException("邊的頂點不存在!");
			 }
			
			 //增加邊的權值
			 matrix[x][y]=value;
			 
		 }
		 
		 /**
		  * Dijkstra演算法實現到各點的最短路徑
		  * @param start
		  */
		 
		 public void dijkstra(int start)
		 {
			 int length =mapping.length;
			 int x=-1;   //記錄起始點
			 for(int i=0;i<length;i++)
			 {
				 if(mapping[i]==start)
				 {
					 x=i;
					 break;
				 }
			 }
			 if(x==-1)
			 {
				 throw new RuntimeException("未找到起始頂點");
			 }
			 
			 //自動初始化為0,都屬於未得到最短路徑的頂點
			 int[]s=new int[length];
			 //儲存v到u的最短距離
			 int [][] distance=matrix;
			 //儲存x到u最短路徑時u的前一個頂點
			 int []path=new int[length];
			 
			 //初始化path陣列
			 for(int i=0;i<length;i++)
			 {
				 //如果可達就賦值
				 if(matrix[x][i]>0)
				 {
					 path[i]=x;
				 }
				 else
				 {
					 //不可達,則賦前一個頂點下標為-1
					 path[i]=-1;
				 }
			 }
			 
			 //先把起始頂點加入s
			 s[x]=1;
			 
			 for(int i=0;i<length;i++)
			 {
				 //首先需要尋找start頂點到各頂點最短的路徑
				 int min=Integer.MAX_VALUE;
				 int v=0;  //記錄x到各頂點最短的
				 for(int j=0;j<length;j++)
				 {
					  if(s[j]!=1&&x!=j&&distance[x][j]!=0&&distance[x][j]<min)
					  {
						  min=distance[x][j];
						  v=j;
					  }
				 }
				  //v 是目前x到各頂點最短的
				 s[v]=1;
				 //修正最短路徑distance及最短距離path
				 
				 for(int j=0;j<length;j++)
				 {
					 if(s[j]!=1&&distance[v][j]!=0&&(min+distance[v][j]<distance[x][j]||distance[x][j]==0))
					 {
						 //說明加入了中間頂點之後找到了更短的路徑
						 distance[x][j]=min+distance[v][j];
						 path[j]=v;
						 
					 }
				 }
				 
			 }
			 
			 //列印最短路徑值
			 Stack <Integer>stack=new Stack<Integer>();
			 for(int i=0;i<length;i++)
			 {
				 if(distance[x][i]!=0)
				 {
					 System.out.println(mapping[x]+"-->"+mapping[i]+"  最短路徑長度:"+distance[x][i]);
					 
					 //path儲存路徑,可以逆序輸出,可以藉助棧實現正序輸出
					 System.out.print("逆序最短路徑輸出:");
					 int index=i;
					 while(index!=-1)
					 {
						 System.out.print(mapping[index]+" ");
						 stack.push(mapping[index]);
						 index=path[index];
					 }
					 System.out.print("正序最短路徑輸出:");
					 while(!stack.isEmpty())
					 {
						 System.out.print(stack.pop()+" ");
					 }
					 System.out.println();
				 }
			 }
			
			 
		 }
		 

	public static void main(String[] args) {
		int[] vetexes={1,2,3,4,5,6};
		Dijkstra graph=new Dijkstra(vetexes);
		graph.addEdge(1, 2,16);graph.addEdge(2, 1,16);
		graph.addEdge(1, 3,1);graph.addEdge(3, 1,1);
		graph.addEdge(1, 5,12);graph.addEdge(5, 1,12);
		graph.addEdge(1, 6,15);graph.addEdge(6, 1,15);
		graph.addEdge(2, 4,2);graph.addEdge(4, 2,2);
		graph.addEdge(2, 6,8);graph.addEdge(6, 2,8);
		graph.addEdge(3, 5,5);graph.addEdge(5, 3,5);
		graph.addEdge(4, 6,3);graph.addEdge(6, 4,3);
		graph.addEdge(5, 6,8);graph.addEdge(6, 5,8);
		graph.addEdge(4, 5,9);graph.addEdge(5, 4,9);
		graph.dijkstra(1);

	}

}