有向有權圖的最短路徑算法--Dijkstra算法


    

Dijkstra算法

1.定義概覽

     Dijkstra(迪傑斯特拉)算法是典型的單源最短路徑算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法是很有代表性的最短路徑算法,

在很多專業課程中都作為基本內容有詳細的介紹,如數據結構,圖論,運籌學等等。注意該算法要求圖中不存在負權邊。

問題描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其余各點的最短路徑。(單源最短路徑)

 

2.算法描述

 

       首先把起點到所有點的路徑花費都設為無窮大(起點到起點的花費設為0),對於一個沒有被標記過的且在沒有標記過的點中從起點到這個點的花費最小(最開始一定是起點)點v,設起點到這個點的花費為v.dist, 如果點v到與它相鄰的點w滿足v.dist + <v,w>.weight < w.dist,其中<v,w>.weight表示從v到w的權值,那么就令w.dist = v.dist + <v,w>.weight ,並把節點v標記(不要標記w),重復以上步驟,直到所有點被標記,所有點的i.dist就是起點到這個點所要的最小花費。

 

3 代碼實現

   按照上述思想,實現代碼即可,圖用鄰接表表示。

 

   

#include <iostream>
using namespace std;
 
#define Inf 65535
#define NotAVerter -1

/////////////////////鄰接表的相關定義//////////////////////
typedef struct EdgeNode *position;
typedef struct Led_table* Table; 


 struct EdgeNode     //邊表結點  
{  
    int adjvex;    // 鄰接點域,存儲該頂點對應的下標  
    int weight;     // 對應邊的權值 
    position next; // 鏈域,指向下一個鄰接點
}; 

struct Led_table       // 鄰接表結構  
{  
    int data;                //鄰接表的大小
    position *firstedge;       //邊表頭指針,可以理解為數組
};  


//////////////////////////鄰接表相關函數定義///////////////
Table Creat_Lable (int MaxElements)    //MaxElements參數為希望創建的節點數
{
	
	Table table1 = static_cast<Table> (malloc(sizeof(struct Led_table)));
	table1->data = MaxElements;
	if (table1 == NULL)
	{
	   cout << "out of space!!!";
	}

	table1->firstedge  = static_cast<position*>(malloc(sizeof(position)*(table1->data))); 
	if (table1->firstedge  == NULL)
	{
	   cout << "out of space!!!";
	}

	//給每個表頭賦值,從0開始
	for (int i = 0; i <= table1->data - 1; ++i)
	{
	    table1->firstedge [i] = static_cast<position>(malloc(sizeof(EdgeNode)));   //申請一個節點
		if (table1->firstedge [i]  == NULL)
			{
			   cout << "out of space!!!";
			}
		table1->firstedge [i]->adjvex = 0;   //表頭這個參數存儲入度
		table1->firstedge [i]->weight = 0;   //此參數在此時沒有意義
		table1->firstedge [i]->next = NULL;

	}
	return table1;

}


void Insert (Table table1, int v, int w, int weig)   //表示存在一條邊為<v,w>,且權重為weig
{
    position p = static_cast<position>(malloc(sizeof(EdgeNode)));   //申請一個節點
	if(p == NULL)
	{
	   cout << "out of space!!!";
	}
	p->adjvex = w;
    p->weight = weig;
	p->next = table1->firstedge [v]->next;
	table1->firstedge [v]->next = p;
		
}


/////////////////////單源無權算法相關定義/////////////////////////
typedef struct unweight_path *unweight_node ;

 struct unweight_path     // 
{  
	bool know;
    int dist;    // 鄰接點域,存儲該頂點對應的下標  
    int path;     // 對應邊的權值 
};

unweight_node unweight_init(Table table1, int start)     //節點初始化
{
	unweight_node Node  = static_cast<unweight_node>(malloc(sizeof(unweight_path)*(table1->data))); 
	if (Node  == NULL)
	{
	   cout << "out of space!!!";
	}
	for(int i = 0; i != table1->data; ++i)
	{
	    Node[i].know = false;
		Node[i].dist = Inf;
		Node[i].path = NotAVerter;
	}
	Node[start].dist = 0;
	return Node;
}

 ////////////////////////單源有權最短路徑算法 Dijkstra /////////////////////////////

 void Dijkstra_Algorithm (Table table1,unweight_node Node)
 {
    int v;
	//用了兩次for循環,時間復雜度較高
	for (int j = 0; j != table1->data; ++j)
	{
	    int zh = Inf;
		for (int i = 0; i != table1->data; ++i)    //找路徑最小且沒有標記過的點
		{
		   if(!Node[i].know && zh > Node[i].dist )  //如果這個點是未知的,且距離比較小
		   {
			  zh = Node[i].dist;
			  v = i;
		   }
	   
		}
		//此時v是距離最小的那個點
		Node[v].know = true;    //標記這個點
		position p = table1->firstedge [v]->next;
		while (p != NULL)   //與這個節點有連接的距離+1
		{
			if(!Node[p->adjvex].know && Node[v].dist + p->weight < Node[p->adjvex].dist )
			{
				Node[p->adjvex].dist = Node[v].dist + p->weight;
				Node[p->adjvex].path = v;
			}
			p = p->next;
		}

	}
	

 }

 /////////////////////打印實際的有權最短路徑///////////////////////////////
 //采用遞歸算法,從后往前推
 void PrintPath (int v, unweight_node Node)    
 {
    if(Node[v].path != NotAVerter)
	{
	  PrintPath (Node[v].path ,Node);
	  cout << " -> ";

	}
	cout  << "v" << v;
 }

int main ()
{
  Table table_1 = Creat_Lable (7);    //創建一個大小為7的鄰接表

  //根據圖來為鄰接表插入數據
  
  Insert (table_1, 0, 1, 2);Insert (table_1, 0, 2, 4);Insert (table_1, 0, 3, 1);
  Insert (table_1, 1, 3, 3);Insert (table_1, 1, 4, 10);
  Insert (table_1, 2, 5, 5);
  Insert (table_1, 3, 2, 2);Insert (table_1, 3, 5, 8);Insert (table_1, 3, 6, 4);
  Insert (table_1, 4, 3, 2);Insert (table_1, 4, 6, 6);
  Insert (table_1, 6, 5, 1);
  
  unweight_node Node_1 = unweight_init(table_1, 0);   //初始化節點
 
 Dijkstra_Algorithm (table_1, Node_1);
   for (int i = 0; i != table_1->data; ++i)
  {
     cout << Node_1[i].dist << '\t';
  }
  cout << endl;
  PrintPath (6, Node_1);
   while(1);
   return 0;
}

  

  對於下圖來說

 

  以v0為起點,到各點的最短路徑為:

下面的v0->v3->v6表示v0到v6的最短路徑經過的點。

 Dijkstra算法是典型的貪婪算法,並不能保證100%的正確率。

  也可參考 http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html  這篇博客的思想,本質上差不多。

  夜深了.....

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM