1. 程式人生 > >最短路徑之迪傑斯特拉算法的Java實現

最短路徑之迪傑斯特拉算法的Java實現

spa visit art 方式 pat fin img 叠代算法 屬於

  Dijkstra算法是最短路徑算法中為人熟知的一種,是單起點全路徑算法。該算法被稱為是“貪心算法”的成功典範。本文接下來將嘗試以最通俗的語言來介紹這個偉大的算法,並賦予java實現代碼。

一、知識準備

1、表示圖的數據結構

  用於存儲圖的數據結構有多種,本算法中筆者使用的是鄰接矩陣。

  圖的鄰接矩陣存儲方式是用兩個數組來表示圖。一個一維數組存儲圖中頂點信息,一個二維數組(鄰接矩陣)存儲圖中的邊或弧的信息。

設圖G有n個頂點,則鄰接矩陣是一個n*n的方陣,定義為:

技術分享

  技術分享

從上面可以看出,無向圖的邊數組是一個對稱矩陣。所謂對稱矩陣就是n階矩陣的元滿足aij = aji。即從矩陣的左上角到右下角的主對角線為軸,右上角的元和左下角相對應的元全都是相等的。

從這個矩陣中,很容易知道圖中的信息。

(1)要判斷任意兩頂點是否有邊無邊就很容易了;

(2)要知道某個頂點的度,其實就是這個頂點vi在鄰接矩陣中第i行或(第i列)的元素之和;

(3)求頂點vi的所有鄰接點就是將矩陣中第i行元素掃描一遍,arc[i][j]為1就是鄰接點;

而有向圖講究入度和出度,頂點vi的入度為1,正好是第i列各數之和。頂點vi的出度為2,即第i行的各數之和。

  有向圖的定義也類似,故不做贅述。

2、單起點全路徑

    所謂單起點全路徑,就是指在一個圖中,從一個起點出發,到所有節點的最短路徑。

3、圖論的基本知識(讀者需自行尋找相關資料)

4、互補松弛條件

 設標量d1,d2,....,dN滿足

    dj<=di + aij, (i,j)屬於A,

 且P是以i1為起點ik為終點的路,如果

    dj = di + aij, 對P的所有邊(i, j)

 成立,那麽P是從i1到ik的最短路。其中,滿足上面兩式的被稱為最短路問題的互補松弛條件。

二、算法思想

1、令G = (V,E)為一個帶權無向圖。G中若有兩個相鄰的節點,i和j。aij(在這及其後面都表示為下標,請註意)為節點i到節點j的權值,在本算法可以理解為距離。每個節點都有一個值di(節點標記)表示其從起點到它的某條路的距離。

  2、算法初始有一個數組V用於儲存未訪問節點的列表,我們暫稱為候選列表。選定節點1為起始節點。開始時,節點1的d1=0, 其他節點di=無窮大,V為所有節點。
初始化條件後,然後開始叠代算法,直到V為空集時停止。具體叠代步驟如下:

   將d值最小的節點di從候選列表中移除。(本例中V的數據結構采用的是優先隊列實現最小值出列,最好使用斐波那契對,在以前文章有過介紹,性能有大幅提示)。對於以該節點為起點的每一條邊,不包括移除V的節點, (i, j)屬於A, 若dj > di + aij(違反松弛條件),則令

  dj = di + aij , (如果j已經從V中移除過,說明其最小距離已經計算出,不參與此次計算)

  可以看到在算法的運算工程中,節點的d值是單調不增的

  具體算法圖解如下

  技術分享

技術分享

三、代碼實現

//接受一個有向圖的權重矩陣,和一個起點編號start(從0編號,頂點存在數組中)
	//返回一個int[] 數組,表示從start到它的最短路徑長度  
	public static int[] Dijsktra(int[][]weight,int start){
		int length = weight.length;
		int[] shortPath = new int[length];//存放從start到各個點的最短距離
		shortPath[0] = 0;//start到他本身的距離最短為0
		String path[] = new String[length];//存放從start點到各點的最短路徑的字符串表示
		for(int i=0;i<length;i++){
			path[i] = start+"->"+i;
		}
		int visited[] = new int[length];//標記當前該頂點的最短路徑是否已經求出,1表示已經求出
		visited[0] = 1;//start點的最短距離已經求出
		for(int count = 1;count<length;count++){
			int k=-1;
			int dmin = Integer.MAX_VALUE;
			for(int i=0;i<length;i++){
				if(visited[i]==0 && weight[start][i]<dmin){
					dmin = weight[start][i];
					k=i;
				}
			}
			//選出一個距離start最近的未標記的頂點     將新選出的頂點標記為以求出最短路徑,且到start的最短路徑為dmin。
			shortPath[k] = dmin;
			visited[k] = 1;
			//以k為中間點,修正從start到未訪問各點的距離
			for(int i=0;i<length;i++){
				if(visited[i]==0 && weight[start][k]+weight[k][i]<weight[start][i]){
					weight[start][i] = weight[start][k]+weight[k][i];
					path[i] = path[k]+"->"+i;
				}
			}
		}
		for(int i=0;i<length;i++){
			System.out.println("從"+start+"出發到"+i+"的最短路徑為:"+path[i]+"="+shortPath[i]);
		}
		return shortPath;
		
	}

  這便是利用迪傑斯特拉算法實現最短路徑的方法。

之後可以聲明一個常量,例如:

static final int MAX = 10000;

然後在main方法裏面建一個鄰接矩陣,調用此方法即可。

public static void main(String[] args) {
		int[][] weight = {
				{0,3,2000,7,MAX},
				{3,0,4,2,MAX},
				{MAX,4,0,5,4},
				{7,2,5,0,6},
				{MAX,MAX,4,6,0}
				};
		int start = 0;
		int[] dijsktra = Dijsktra(weight,start);
	}

  參考自:http://www.cnblogs.com/junyuhuang/p/4544747.html

最短路徑之迪傑斯特拉算法的Java實現