【JAVA演算法】圖論演算法 -- Dijkstra演算法

focus.zhaos發表於2018-03-27

寫在前面:

    我也是一名java語言的愛好者,僅以此文作為學習的記錄,對於文中出現的程式碼規範,程式碼格式,演算法效率等問題,希望各路大神不吝賜教,在下感激不盡。同是學習的同學也同樣希望互相交流,取長補短。                                                                                                                                            

——zsferrier@126.com

Dijkstra演算法是貪心演算法最好的例子,貪婪演算法一般分階段求解一個問題,在每個階段它都把出現的當作最好的去處理。

首先給出資料型別

	//節點所儲存的資料域
	class Vertex{
		public List<Integer> adjacency;//鄰接表
		public boolean known; //標記
		public int dist;	//距離出發點的距離
		public Vertex path;//路徑
		public int vname;//節點編號
		public Vertex(){
			known = false;
			dist = MaxLen;
			path = null;
		}
	}

鄰接表儲存與該節點鄰接所有節點的邊資訊,不直接相鄰的節點距離為MaxLen(預定義,MaxLen=1000表示不距離不可達)

known標記節點是否已知。 

dist為此節點當前距離原點的距離MaxLen表示不可達。

path記錄路徑上的上一個節點。

vname為節點編號。


dijkstra分階段求解,在每個階段,選擇一個節點v,它在所有的unknown節點中具有最小的dist值,納入已知節點。根據該節點的鄰接域(邊的值cvw)來計算其他unknown狀態下的鄰接點w的dist,與Vw的原dist值比較,若v.dist+cvw<w.dist,則更新。

賦權圖


下面給出Dijsktra演算法虛擬碼:

void dijkstra( Vertex s )
{
	for each Vertex v
	{
		v.dist = INFINITY;
		v.known = false;
	}
	s.dist = 0;
	while( there is an unknown distance vertex )
	{
		Vertex v = smallest unknown distance vertex;
		v.known = true;
		for each Vertex w adjacent to v if( !w.known )
		{
			DistType cvw = cost of edge from v to w;
			if( v.dist + cvw < w.dist )
			{
				// Update w 
				decrease( w.dist to v.dist + cvw ); w.path = v;
			}
		}
	}
}


JAVA語言實現:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {

	/**
	 * @param args
	 */
	//節點所儲存的資料域
	class Vertex{
		public List<Integer> adjacency;//鄰接表
		public boolean known; //標記
		public int dist;	//距離出發點的距離
		public Vertex path;//路徑
		public int vname;//節點編號
		public Vertex(){
			known = false;
			dist = MaxLen;
			path = null;
		}
	}
	private static int MaxLen = 1000;//表示不可達
	//有權圖,使用鄰接表來表示圖。
	private static Vertex[] verArray = new Vertex[7];
	//這個函式用來判斷還有沒有unknown distance vertex
	public static boolean judge(){
		for (Vertex v : verArray) {
			if(v.known==false){
				return true;
			}
		}
		return false;
	}
	//這個函式用來返回再unknown中最小的distance vertex
	public static Vertex smallestVertex(){
		int num = 0;
		int value = MaxLen;
		for (int i = 0; i < verArray.length; i++) {
			if((verArray[i].known==false)&&(verArray[i].dist<value)){
				num = i;
				value = verArray[i].dist;
			}
		}
		return verArray[num];
	}
	public static void dijkstra(int s){
		verArray[s].dist = 0;//起點的dist為零
		while(judge()){
			Vertex vtex = smallestVertex();
			vtex.known = true;
			for (Integer i : vtex.adjacency) {
				if(!verArray[vtex.adjacency.indexOf(i)].known){
					if (vtex.dist+i<verArray[vtex.adjacency.indexOf(i)].dist) {
						//Update
						verArray[vtex.adjacency.indexOf(i)].dist = vtex.dist+i;
						verArray[vtex.adjacency.indexOf(i)].path = vtex;
					}
				}
			}
		}
	}
	//輸出路徑函式
	public static void printGraph(Vertex v){
		if(v.path!=null){
			printGraph(v.path);
		}
		System.out.print("V"+v.vname+"  ");
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//初始化
		verArray[0] = new Main().new Vertex();
		verArray[1] = new Main().new Vertex();
		verArray[2] = new Main().new Vertex();
		verArray[3] = new Main().new Vertex();
		verArray[4] = new Main().new Vertex();
		verArray[5] = new Main().new Vertex();
		verArray[6] = new Main().new Vertex();
		verArray[0].adjacency = new ArrayList<Integer>(Arrays.asList(0,2,MaxLen,1,MaxLen,MaxLen,MaxLen));
		verArray[0].vname = 0;
		verArray[1].adjacency = new ArrayList<Integer>(Arrays.asList(MaxLen,0,MaxLen,3,10,MaxLen,MaxLen));
		verArray[1].vname = 1;
		verArray[2].adjacency = new ArrayList<Integer>(Arrays.asList(4,MaxLen,0,MaxLen,MaxLen,5,MaxLen));
		verArray[2].vname = 2;
		verArray[3].adjacency = new ArrayList<Integer>(Arrays.asList(MaxLen,MaxLen,2,0,2,8,4));
		verArray[3].vname = 3;
		verArray[4].adjacency = new ArrayList<Integer>(Arrays.asList(MaxLen,MaxLen,MaxLen,MaxLen,0,MaxLen,6));
		verArray[4].vname = 4;
		verArray[5].adjacency = new ArrayList<Integer>(Arrays.asList(MaxLen,MaxLen,MaxLen,MaxLen,MaxLen,0,MaxLen));
		verArray[5].vname = 5;
		verArray[6].adjacency = new ArrayList<Integer>(Arrays.asList(MaxLen,MaxLen,MaxLen,MaxLen,MaxLen,1,0));
		verArray[6].vname = 6;
		//起點從v0開始
		dijkstra(0);
		for (Vertex v : verArray) {
			System.out.print("到節點V"+v.vname+"的最短路徑為:     ");
			printGraph(v);
			System.out.println();
		}
	}
}

控制檯輸出


這裡注意一點,我定義的Vertex是個內部類,在主函式中如果直接使用new動態申請記憶體的時候會出現這樣的錯誤。

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
	No enclosing instance of type Main is accessible. Must qualify the allocation with an enclosing instance of type Main (e.g. x.new A() where x is an instance of Main).

	at DijkstraAlg.Main.main(Main.java:75)
報錯位置為
		verArray[0] = new Vertex();

這是由於Java中的內部類沒有使用static修飾,其建構函式被認為是一個動態方法,而主函式main為靜態函式,不能直接呼叫,解決的方法為在new Vertex前加上外部類,即:

		verArray[0] = new Main().new Vertex();


                                                                             轉載請標明出處,謝謝 by zsferrier@126.com



相關文章