Dijkstra算法探索及優化

         (前幾天並多少時間,現在補充一下!)下面是原始的dijkstra算法:

   

public static void dijkstra(int v,float[][] a, flaot[] dist,int[] prev)
{
int n=dist.length-1;
if(v<1||v>n)return;
boolean[] s = new boolean[n+1];
//此處的循環是初始化
 for(int i=1; i<=n; i++)
{
dis[i]=a[v][i];
s[i]= false;
if(dist[i]==Float.MAX_VALUE)prev[i]=0;
else prev[i]=v;
}
//此處開始遍歷
 dist[v]=0; s[v]=true;
//該循環是求的所有節點到源節點的路徑,每循環一次求的一個節點到源節點的距離
 for(int i=1; i<n; i++)
{
float temp = Float.MAX_VALUE;
int u=v;
//shortestPath(此處取該循環爲shortestPath)
 for(int j=1; j<n; j++)
{
if((!s[j])&&(dist[j]<temp))
{
u=j;
temp=dist[j];
}
}
s[u]=true;
//updateDist(取名爲updateDist)
 for(int j=1; j<n; j++)
{
if((!s[j])&&(a[u][j]<Float.MAX.VALUE))
{
float newdist = dist[u]+a[u][j];
if(newdist<dist[j])
{
dist[j]=newdist;
prev[j]=u;
}
}
}
}
}


        

         以前看過Dijkstra算法,但是一直沒有深入的研究它!最近由於項目的需要,所以今天研究了一下!下面介紹一下這個算法幾個重要的幾點!

          其實這個算法有兩個比較重要的地方!在書上開始有一個循環,是對參數初始化。這個就沒必要研究了!主要的是第二個循環裏面的兩個循環,第二個循環要進行n-1次(也就是循環節點個數減去源節點),這就是要取得其他節點到源節點的距離,一次循環就是取得一個節點到源節點的距離。那麼在第二個循環裏面的第一個循環(這裏叫該循環爲shortestPath)就是取得當前能夠到達源節點最短的節點,並且該節點是未被訪問過的節點。取得在未被訪問的節點裏面到源節點最短路徑的節點u後,最一個循環就是修改和u節點相連的節點到源節點的距離(這裏稱該循環爲updateDist),我這裏稱這一步爲更新u的鄰接節點到源節點的距離。再回到shortestPath循環,就有可能取到u的鄰接節點。下面我談談對這個算法的改進。

          我們知道在shortestPath循環中,在書上的源碼都是要遍歷圖中所有的節點,這樣我覺得存在極大的浪費,我們知道該步是取得在dis數組中到源節點最短的節點,並且該節點是未被訪問過的,所以這裏根本沒必要遍歷圖中所有的節點,只需遍歷dis數組中的節點,而且我們知道dist的新的距離都是通過updateDist循環得到的,所以我們完全可以將dist數組裏的距離存儲到一個集合中,我們可以自定義一個集合,當我們每次想該集合添加元素(也就是到源節點的距離)的時候自動對該集合中進行排序,進行遞增排序,我們取該集合的第一個元素就是當前到源節點最短的節點,並且該節點是未被訪問的,取出時並將該節點從該集合中移出。這樣我們就省掉了shortestPath這個循環了,這樣對算法的運行將有極大的提高!還有就是後面的updateDist循環,在書上的源碼中也是對圖中的所有節點進行遍歷,其實也沒必要,只需對u的領結節點遍歷即使!這樣有省掉了沒必要的循環,這樣的Dijkstra算法,我相信應該不會很慢!

          注意的是這種優化也需要對你的圖結構進行優化,具體的優化可以見本博客的《新穎的圖存儲結構【看來之後你會對圖的結構有新的想法】》文章,裏面有詳細講解一種圖的存儲結構!

         下面貼出我改進的算法:

        

public class ShortestPathIterator_3 {

	private Graph graph;
	private boolean visited[];
	private int prev[];
	private int source;
	private int position;
	private float pathCost[];
	private int n;
	private Map<Integer,Float> visitable;
	//獲得當前的源節點
	public int getSource()
	{
		return this.source;
	}
	public ShortestPathIterator_3(Graph graph,int source)
	{
		visited = new boolean[graph.getNode_Count()];
		this.visitable = new HashMap<Integer,Float>();
		prev = new int[graph.getNode_Count()];
		this.graph = graph;
		this.source = source;
		this.pathCost = new float[this.graph.getNode_Count()];
		for(int i=0; i<graph.getNode_Count(); i++)
		{
			this.pathCost[i]=Float.MAX_VALUE;
			this.visited[i]=false;
		}
		EdgeIterator edgeIterator = graph.getEdgeIterator(this.source);//獲得所有和元節點相鄰的節點集合
		int adjancentNode;
		while(edgeIterator.hasNext())
		{
		    adjancentNode = this.graph.getAdjancentNode(edgeIterator.next());	
		    this.pathCost[adjancentNode] = this.graph.getEdgePrestige(edgeIterator.next());
		    this.visitable.put(adjancentNode, this.graph.getEdgePrestige(edgeIterator.next()));
			this.prev[adjancentNode] = this.source;
		}
	    
	  	this.visited[this.source]=true;
	  	this.position=0;
	  	this.n=this.graph.getNode_Count()-1;
	  	
	}
	public int getNext()
	{
		Integer u = this.source;
		if(this.position<=this.n-1)
		{
			float temp = Float.MAX_VALUE;
	        Iterator<Integer> keyIterator = this.visitable.keySet().iterator();
	        int next; 
	        //取得未被訪問並且,到源點最短的節點,並賦值給U,同時將和U相連的節點到源點的距離進行更新
			while(keyIterator.hasNext())
			{
				next= keyIterator.next();
				if(this.visitable.get(next)<temp)
				{
				    u=next;
					temp = this.visitable.get(next);
				}
			}
			this.visited[u]=true;
			//更新和u相連的節點到源點的距離
			updatePathCost(u);
			this.visitable.remove(u);
			this.position++;
			return u;
		}
		else
		{
			return -1;
		}
		
		
	}
	public void updatePathCost(int u)
	{
		float newPathCost;
		EdgeIterator edgeIterator = this.graph.getEdgeIterator(u);//獲得所有和u節點相鄰的節點集合
		int adjancentNode;
		while(edgeIterator.hasNext())
		{
			adjancentNode = this.graph.getAdjancentNode(edgeIterator.next());
			//將還未被訪問的節點進行判斷到源點的距離
			if(!this.visited[adjancentNode])
			{
		newPathCost = this.getPathCost(u)+this.graph.getEdgePrestige(this.graph.getEdgeId(adjancentNode, u));
		if(newPathCost<this.getPathCost(adjancentNode))
				{
					this.visitable.put(new Integer(adjancentNode), newPathCost);
					this.pathCost[adjancentNode] = newPathCost;
					this.prev[adjancentNode]=u;
				}
			}
		}
	}
	public float getPathCost(int node)
	{
		return this.pathCost[node];
	}
	public int getPrevNode(int node)
	{
		return this.prev[node];
	}
}


           這個優化我已經實現了!需要深入探討的可以和我聯繫。希望能夠幫助和我以前一樣的人!謝謝瀏覽!

發佈了40 篇原創文章 · 獲贊 26 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章