最短路徑Floyd演算法具體演示
演示作品下載
最短路徑Floyd演算法具體演示
----用VC++來實現路由選擇演算法
摘要:
確定圖的路由選擇的策略要考慮很多技術因素。其包括:選擇最短路由還是最佳路由;Floyd提出圖的求每一對頂點之間最短路徑的方法,由於好多教材採用的是字元介面演算法演示,不是很直觀,而且不符合當前windows介面程式設計趨勢。為此,經過反覆的探索和實踐,充分結合VC++強大而靈活的程式設計模式,基於對話方塊MFC,成功完成看似頗難的任務。為後續的進一步演變,創造了一個良好的基礎原型。
關鍵字:
網路節點,路由選擇,圖,有向圖和無向圖,頂點,最短路徑,臨接矩陣,Floyd演算法,
正文:
通訊子網為網路源節點和目的節點提供多條傳輸資料的路徑。網路是節點在收到一個分組後。要確定向下一個節點傳送的路徑,這就是路由選擇。路由選擇是網路層要實現的基本功能。在資料報方式中,網路節點要為每個分組選擇路由;而在虛電路方式中,只需在連線建立時確定路由。
若要建立一個路由資訊系統,可用一個帶權的圖來表示一個網路。用圖的頂表示地點,用圖中的邊表示兩地之間的資訊路線,每條邊上所附的權值表示該路線的----------。根據實際情況,該圖可以是有向圖和無向圖。我們暫以最短路徑表示其權值。在圖甲所示的帶權的有向圖中,從V0到V2有兩條不同路徑:(V0,V1,V2)和(V0,V3,V4,V2),前者路徑長度為
如果給定一個出發點(單源點)和一個有向網 G=(V,E),欲求出源點到其他各定點之間的最短路徑,迪傑斯特拉(Dijkstra)提出了按路徑長度的遞增次序,逐步產生最短路徑的演算法。演算法思想:設集合S存放已經求出的最短路徑的終點,初始狀態時,集合S中只有一個源點,不妨設為V0。以後每求得一條最短路徑(V0,V1,…,Vk),就將Vk加入到集合S中,直到全部頂點都加入到集合S中。
為此引入一個附助陣列dist[],它的每一個分量dist[i]表示當前從源點V0到Vi的最短路徑長度。它的初始狀態:若從源點V0到頂點Vi有邊,則dist[i]為該邊上的權值;若從源點到頂點
顯然,路徑長度為dist[j]=min{dist[I]|Vi∈V-v0}的路徑是從V0出發的長度最短路徑,即為(V0,Vj),隨即將Vj加入到集合S中。如何求得下一條最短路徑?由於V0到Vj的最短路徑已求得,可能引起V0到其餘頂點的當前最短路徑長度發生變化,V0到Vk的當前最短路徑長度只能是(V0,Vk)和(V0,Vj,Vk)的小者。
假設S是已求得的最短路徑的終點集合,可以證明:下一條最短路徑(設終點為Vt)或者是(V0,Vt),或者是中間只經過S中頂點便可到達頂點Vt的路徑。這可以用反證法證明:設在此路徑上存在一個頂點Vp不在S中,則說明V0到Vp的路徑長度比V0到Vt的最短路徑長度還短。然而這是不可能的,因為我們是按照最短路徑長度遞增的次序來逐次產生各條最短路徑的,因此,長度比這條路徑短的所有路徑均已產生,而且它們的終點也一定已在集合S中,故假設不成立。
因此,在一般情況下,下一條長度最短最短路徑長度為dist[k]=min{dist[i]/Vi∈V-S}
在每次求得一條最短路徑之後,其終點Vk加入集合S,然後對所有的Vi∈V-S,修改其當前最短路徑長度dist[i]=min{dist[i],dist[k]+Edge[k][i]},其中,Edge[k][i]是邊(Vk,Vi)上的權值。下面給出Dijkstra演算法:
const int NumVer=0;//
class Graph
{
private:
float Edge[NumVex][NumVex];//圖的臨接矩陣
float dist[NumVex];//存放從頂點V到其它各頂點的當前最短路徑長度。
int path[NumVex];
int S[NumVex];//存放已求得的在最短路徑上的頂點
public:
void ShortestPath_Dijkstra(int ,int);
int choose(int);
};
void Graph::ShortestPath_ Dijkstra(int n ,int v)
{
for(int i=0;i<n;i++)
{
//dist,path,S的初始化
dist[i]=Edge[v][i];
S[i]=0;
If(I!=v;&&dist[I]<MAXNUM)
path[I]=v;
else
Path[I]=-1;
}
s[v]=1;
dist[v]=0;//頂點v加入已求出最短路徑的頂點集合
for(i=0;i<n-1;i++)
{
float min=MAXNUM;
int u=v;
for(int j=0;j<n;j++)//選擇當前不在集合S中具有最短路徑的頂點u
if(!S[j]&&dist[j]<min)]
{
u=j;
min=dist[j];
}
S[u]=1;//頂點u加入已求出最短路徑的頂點集合
for(int w=0;w<n;w++) //修改其餘頂點的當前最短路徑
if(!S[w]&&Edge[u][w]<MAXNUM&&dist[u]+Edge[u][w]<dist[w])
{
dist[w]=dist[u]+Edge[u][w];
path[w]=u;
}
}
}
如果要按求出每對頂點之間的最短路徑,須分別以每個頂點為源點,重複執行Dijkstra演算法。這樣就求得每對頂點之間的最短路徑及最短路徑長度.我們使用更直接求解演算法,稱為Floyd(弗洛伊德)演算法。
帶權有向圖仍然用鄰接矩陣Edge[n][n]表示,Dijkstra演算法的基本思想是:設定一個n*n的方陣dist[n][n],初始化時,對角線的元素都等於零,表示頂點到自己的路徑長度為0,其他元素dist[i][j]為Edge[i][j]的值,表示從頂點Vi到的頂點Vj的初試路徑長度。該路徑不一定是最短路徑,尚需進行n次試探。首先考慮頂點V0作為中間頂點,判斷路徑(Vi,V0,Vj)是否存在,即(Vi,V0)和(V0,Vj)是否存在。如果存在,取(Vi,Vj)與(Vi,V0,Vj)的小者為Vi到Vj的當前的最短路徑長度distj[i][j],也就是Vi到Vj經過的中間頂點序號不大於0的最短路徑長度。其次中間頂點序號可增加考慮頂點V1,因為dist[i][1]和dist[1][j]分別為Vi到V1和V1到Vj經過的中間頂點序號不大於0的最短路徑長度,所以dist[i][1]+dist[1][j]與dist[i][j]的小者即為Vi到Vj經過的中間頂點序號不大於1的最短路徑長度,作為當前最短路徑長度dist[i][j].然後再增加考慮頂點V2,以此類推,考慮所有n個頂點後,dist[i][j]的值就是Vi到Vj的最短路徑的長度。
由於好多教材採用的是字元介面演算法演示,不是很直觀,而且不符合當前windows介面程式設計趨勢。為此,經過反覆的探索和實踐,充分結合VC++強大而靈活的程式設計模式,基於對話方塊MFC,成功完成看似頗難的任務。
從下圖介面可知,此帶權有向圖頂點假設為V0,V1,…V18,V19,共20個,兩點之間有單向的,也有雙向的。有向圖實際分成兩個不相通的兩部分。如果使用者任選兩個頂點,比如V0及V13(注意:先點選V0的為源點,後點擊的V13為目的點,超過兩個或一個無效),然後點選開始按鈕,通過後臺的一系列介面事件處理程式碼及Floyd(弗洛伊德)演算法運算,然後把路徑顯示在相應視窗中,比如13<<9<<5<<6<<4<<0,它代表路徑為:V0->V4->V6->V5->V9->V13同時。路徑總長為47。如果兩頂點不通,路徑及總長度無效。
下面分析一下其中主要演算法:
首先在CGraphFloydDlg中,建立三個private的變數:
intiVertexFlag1;
intiVertexFlag2;
intiVertexSelected;
控制源及目的頂點的選擇及順序。
然後在CGraphFloydDlg的實現檔案中,建立
int Edge[20][20];
int Dist[20][20];
int Path[20][20];//其中Path[i][j]是相應路徑上頂點j的前一頂點的頂點號。
const int MAXNUM = 9999;//
找到BOOL CGraphFloydDlg::OnInitDialog()函式,在其中新增如下程式碼:
…
// TODO: Add extra initialization here
iVertexSelected=0;
iVertexFlag1=-1;
iVertexFlag2=-1;
for(int i=0;i<20;i++)
for(int j=0;j<20;j++)
{
if(i==j)
Edge[i][j]=0;
else
Edge[i][j]=MAXNUM;
}
Edge[0][2]=20,Edge[0][4]=12;
Edge[1][0]=10;
Edge[2][5]=22;
Edge[3][1]=14;
Edge[4][3]=33,Edge[4][6]=8;
Edge[5][4]=11,Edge[5][9]=7;
Edge[6][4]=8,Edge[6][5]=6,Edge[6][12]=56;
Edge[7][8]=13,Edge[7][10]=19,Edge[7][11]=16;
Edge[8][7]=13;
Edge[9][5]=7,Edge[9][13]=14;
Edge[10][14]=22;
Edge[11][7]=16,Edge[11][14]=77,Edge[11][15]=13;
Edge[12][6]=56,Edge[12][13]=21;
Edge[13][12]=21,Edge[13][16]=8,Edge[13][17]=22;
Edge[14][11]=77 ,Edge[14][19]=9 ;
Edge[15][11]=13,Edge[15][18]=11;
Edge[16][17]=23;
Edge[17][12]=26;
Edge[18][15]=11;
Edge[19][18]=88;
…
通過以上程式碼完成對圖的頂點選擇變數及臨接矩陣的初始化。鄰接矩陣的初始值實為上述圖片中,所標註的頂點之間的值。
假如選擇V0頂點時,將要觸發
void CGraphFloydDlg::OnV0()
{
// TODO: Add your control notification handler code here
CButton *p0=(CButton *)GetDlgItem(IDC_V0);
if((!p0->GetCheck())&&(iVertexSelected>0))
{
iVertexSelected--;
if(iVertexFlag1==0)
{
iVertexFlag1=iVertexFlag2;
iVertexFlag2=-1;
}
else if(iVertexFlag2==0)
iVertexFlag2=-1;
}
else if((iVertexSelected==0)&&(p0->GetCheck()))
{
iVertexSelected++;
iVertexFlag1=0;
}
else if((iVertexSelected==1)&&(p0->GetCheck()))
{
iVertexSelected++;
iVertexFlag2=0;
}
else if((iVertexSelected>=2)&&(p0->GetCheck()))
{
AfxMessageBox("頂點數不容許超過2個!");
p0->SetCheck(FALSE);
}
}
假如選擇V13頂點時,將要觸發
void CGraphFloydDlg::OnV13()
{
// TODO: Add your control notification handler code here
CButton *p13=(CButton *)GetDlgItem(IDC_V13);
if((!p13->GetCheck())&&(iVertexSelected>0))
{
iVertexSelected--;
if(iVertexFlag1==13)
{
iVertexFlag1=iVertexFlag2;
iVertexFlag2=-1;
}
else if(iVertexFlag2==13)
iVertexFlag2=-1;
}
else if((iVertexSelected==0)&&(p13->GetCheck()))
{
iVertexSelected++;
iVertexFlag1=13;
}
else if((iVertexSelected==1)&&(p13->GetCheck()))
{
iVertexSelected++;
iVertexFlag2=13;
}
else if((iVertexSelected>=2)&&(p13->GetCheck()))
{
AfxMessageBox("頂點數不容許超過2個!");
p13->SetCheck(FALSE);
}
}
一方面判斷頂點的選擇順序情況,修改相應的變數,另一方面,控制使用者選擇的數量,如果不符合要求,會取消當前操作。
對於其他頂點的觸發,同樣會執行類似的函式。
當用戶選擇好頂點時,點選開始按鈕,將執行如下函式:
void CGraphFloydDlg::OnStart()
{
// TODO: Add your control notification handler code here
if(iVertexSelected==2)
{
for( int i=0;i<20;i++)
for(int j=0;j<20;j++)
{
Dist[i][j]=Edge[i][j];//初始化dist
if((i!=j)&&Dist[i][j]<MAXNUM)
Path[i][j]=i;
else
Path[i][j]=-1;
}
for(int k=0;k<20;k++)//逐次增加中間頂點k
for(int m=0;m<20;m++)
for(int n=0;n<20;n++)
{
if(Dist[m][k]+Dist[k][n]<Dist[m][n])//當前最短路徑經過中間頂點k
{
Dist[m][n]=Dist[m][k]+Dist[k][n];
Path[m][n]=Path[k][n];
}
}
m_iMinLen=Dist[iVertexFlag1][iVertexFlag2];
int iPath=iVertexFlag2;
m_strVs="";
CString strTemp;
strTemp.Format("%d<<",iVertexFlag2);
m_strVs+=strTemp;
while(Path[iVertexFlag1][iPath]>-1)
{
strTemp.Format("%d<<",Path[iVertexFlag1][iPath]);
m_strVs+=strTemp;
iPath=Path[iVertexFlag1][iPath];
}
m_strVs.TrimRight("<<");
if(m_iMinLen==MAXNUM)
{
m_iMinLen=-1;
m_strVs="此路不通!";
}
UpdateData(FALSE);
}
else
{
m_strVs=" 請選則兩個有向點。";
m_iMinLen=-1;
UpdateData(FALSE);
}
}
程式碼首先判斷頂點選擇數量是否為合法的二個,如果是,執行Floyd(弗洛伊德)演算法,求出最短路徑的長度及最短路徑字串。如果只選擇一個頂點或兩個頂點路徑不通,給出提示資訊。
確定路由選擇的策略要考慮很多技術因素。其包括:選擇最短路由還是最佳路由;通訊子網採用虛電路操作方式,還是資料報操作方式;採用分散式路由演算法,還是集中式路由演算法;採用靜態路由選擇策略,還是動態路由選擇策略等。所以,路由選擇演算法(Routing Algorithm)以及它們使用的資料結構是網路層涉及的一個重要研究領域。
演示作品下載
想具體瀏覽原始碼請和作者本人聯絡。
聯絡方式:
參考文獻:
1.嚴蔚敏,吳偉民.資料結構(C語言版).北京:清華大學出版社,1996
2.張福炎.《〈程式設計師高階程式設計師程式設計及〉》(第二版). 北京:清華大學出版社,1996
3.黃劉生,唐策善:《《資料結構》》第二版,中國科學技術大學出版社,2000
相關推薦
最短路徑Floyd演算法具體演示
演示作品下載 最短路徑Floyd演算法具體演示 ----用VC++來實現路由選擇演算法 摘要: 確定圖的路由選擇的策略要考慮很多技術因素。其包括:選擇最短路由還是最佳路由;
最短路徑—Floyd演算法
Floyd演算法: 1,從任意一條單邊路徑開始。所有兩點之間的距離是邊的權,如果兩點之間沒有邊相連,則權為無窮大。 2,對於每一對頂點 u 和 v,看看是否存在一個頂點 w 使得從 u 到 w 再到 v 比已知的路徑更短。如果是更新它。 Floyd-Warshall——
【資料結構】所有頂點對的最短路徑 Floyd演算法
所有頂點對的最短路徑問題是指:對於給定的有向圖G=(V,E),求任意一對頂點之間的最短路徑。 可以求解得到的 的遞推公式: #include <stdio.h> #include <stdlib.h> const int FINI
圖-最短路徑-Floyd演算法
給定高鐵的規劃方案,如何求任意兩點的最短路呢? 方法是Floyd演算法。 演算法思想: 1、計算從i出發,跳點為空,直接到j 的最短路。記做D[i][j]。 2、可選跳點為1時,i到j的路徑分為兩種情況: 或者不經過1, 此時前者最短為D[i][j], 或者經過1
最短路徑---Floyd演算法(C++)
Floyd演算法的介紹 演算法的特點: 弗洛伊德演算法是解決任意兩點間的最短路徑的一種演算法,可以正確處理有向圖或有向圖或負權(但不可存在負權迴路)的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。 演算法的思路 通過Floyd計算圖G=(V,E)中各個頂點的最短路徑時,需要引入
多源最短路徑--Floyd演算法
#include<iostream> #include<cstdio> using namespace std; const int INF = 0x3f3f3f3f; int main(void) { int e[10][10] = { 0 }, dis[10], boo
每一對頂點之間的最短路徑----Floyd演算法----(附完整程式碼)
1.Floyd演算法 2.輸出每兩對頂點之間的最短距離 #include<stdio.h> #include<stdlib.h> #define MaxVertexNum 100 #define INFINITY 65535 //#define MaxSize 1
最短路徑-Floyd演算法的matlab實現.md
最短路徑-Floyd演算法的matlab實現 弗洛伊德演算法是解決任意兩點間的最短路徑的一種演算法,可以正確處理有向圖或有向圖或負權(但不可存在負權迴路)的最短路徑問題。 在Floyd演算法中一般有兩個矩陣,一個距離矩陣D,一個路由矩陣R,其中距離矩陣用
最短路徑 Floyd演算法 Dijkstra演算法 Bellman-Ford(貝爾曼)演算法
相信大家應該對最短路徑演算法很感興趣吧!不感興趣也沒關係,我們一起來看看下面的例子。最短路徑應該是在眾多演算法中。最常用的一類演算法。為什麼這樣說呢?? 例如: 1.乘汽車旅行的人總希望找出到目的地的儘可能的短的行
最短路徑(Floyd演算法)
Floyd演算法又稱為弗洛伊德演算法,插點法,是一種用於尋找給定的加權圖中頂點間最短路徑的演算法。 標頭檔案:Floyd.h #ifndef FLOYD_H #define FLOYD_H #define INFINITY 65535 #define MAXVEX 2
求有向網中任意一對頂點之間的最短路徑 Floyd演算法
有向網中欲知任意一對頂點之間的最短路徑常用Floyd演算法,基本思想是任意一對頂點vi與vj,逐步在其中加入一箇中間節點v0,..,vk,...vn,若比原路徑短則更新最短路徑,經過n次比較和修正後,vi到vj的最短路徑可以求出。具體程式碼及相關注釋如下 //
最短路徑-Floyd(弗洛伊德)演算法
最短路徑-Floyd(弗洛伊德)演算法 簡介: 相較Dijkstra,Floyd是一個完全窮舉圖中每個點到末尾點的最短路徑 演算法思想: 按慣例說兩個工具 Path[MAX_SIZE][MAX_SIZE]:儲存所有的最短路徑(指向
圖-最短路徑—Dijkstra演算法和Floyd演算法
1.定義概覽 Dijkstra(迪傑斯特拉)演算法是典型的單源最短路徑演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止。Dijkstra演算法是很有代表性的最短路徑演算法,演算法使用了廣度優先搜尋解決賦權有向圖或者無向圖的單源
結點對最短路徑Floyd弗洛伊德演算法解析
暑假,小哼準備去一些城市旅遊。有些城市之間有公路,有些城市之間則沒有,如下圖。為了節省經費以及方便計劃旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。 上圖中有4個城市8條公路,公路上的數字表示這條公路的長短。請注意這些公
紫書第十一章-----圖論模型與演算法(最短路徑Dijkstra演算法Bellman-Ford演算法Floyd演算法)
最短路徑演算法一之Dijkstra演算法 演算法描述:在無向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其餘各點的最短路徑。 使用條件:單源最短路徑,適用於邊權非負的情況 結合上圖具體搜尋過程,我繪出下表,方便
圖的最短路徑-Dijkstra演算法和Floyd演算法
Dijkstra演算法 單源點最短路徑問題 Dijkstra演算法主要用來解決單源點最短路徑問題。 給定帶權有向圖G=(V,E),其中每條邊的權是非負數。另外,還給定V中的一個頂點,稱為源。現在要計算從源到所有其他各頂點的最短路徑長度,這裡路徑的長度是指路徑上各邊權之和。這個問題
最短路徑Dijkstar演算法和Floyd演算法詳解(c語言版)
轉載請註明出處:http://blog.csdn.net/crescent__moon/article/details/16986765 先說說Dijkstra吧,這種演算法只能求單源最短路徑,那麼什麼是單源最短路徑呢?就是隻能求一個點到別的點最短路徑,而不能求所有點到其它
最短路徑-Floyd算法(轉載)
進一步 數字 sdn 進行 無法 .net %d data scanf 暑假,小哼準備去一些城市旅遊。有些城市之間有公路,有些城市之間則沒有,如下圖。為了節省經費以及方便計劃旅程,小哼希望在出發之前知道任意兩個城市之前的最短路程。 上圖
【模板】單源最短路徑——Floyd
表示 而且 鄰接 正是 內容 tle code spa 可能 抱歉這幾天 晚上一直認真 (頹廢)打模擬賽 一直沒寫博客 然後今天學了最短路 然後 馬上過來碼一下 以下內容 有的是搬得那些大佬們得博客 也謝謝他們 1.Floyd 感覺
多源最短路徑 – Floyd-Warshall Algorithm
min algo ron 介紹 表示 解決 路徑 計算 最短距離 介紹: 是解決任意兩點間的最短路徑的一種算法,可以正確處理有向圖或負權(但不可存在負權回路)的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。 Floyd-Warshall算法的時間復雜度是O(N3)