迪傑斯特拉(dijkstra)算法:求最短路徑的算法,數據結構課程中學習的內容。
1 . 理解
算法思想::設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以后每求得一條最短路徑 , 就將 加入到集合S中,直到全部頂點都加入到S中,算法就結束了),第二組為其余未確定最短路徑的頂點集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。
算法的實現步驟:
(1)初始時,S只包含源點,即S=,v的距離為0。U包含除v外的其他頂點,U中頂點u距離為邊上的權(若v與u有邊)或 )(若u不是v的出邊鄰接點)。
(2)從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。
(3)以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u(u U)的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改后的距離值的頂點k的距離加上邊上的權。
(4)重復步驟(2)和(3)直到所有頂點都包含在S中。
具體實現的思考:
minlen(i)=min{minlen(i),minlen(j)+a[j][i]}
其中,i為目標點,j為i之前的一點,遍歷其他所有的點為j,如果不相鄰,則a[j][i]=Max。
由此實現如下代碼。
2 . c語言初步實現
#include <stdio.h>
#include <stdlib.h>
#define N 7
#define Max 0x0fffffff
typedef struct _node
{
int way[N-1];
int len;
}node;
void addWay(node *nd,int n,int type)//type=1表示找到新的最小路徑,type=0表示找到最小路徑
{
int i=0;
while(nd->way[i]!=0&&i<N-1)
{
i++;
}
if(i>=N-1)
{
printf("The node's way[] is full.");
}
else
{
if(0==type)
nd->way[i]=n;
if(1==type)
nd->way[i-1]=n;
}
}
void dkstra(node nd[],int (*a)[N])
{
int i=0,j=0;
for(i=1;i<N;i++)
{
int tag=0;
for(j=0;j<N;j++)
{
if(nd[i].len<Max&&nd[j].len+a[j][i]<Max)
tag=1;
nd[i].len<=(nd[j].len+a[j][i])?(nd[i].len=nd[i].len):(nd[i].len=(nd[j].len+a[j][i]),addWay(&nd[i],j+1,tag));
tag=0;
}
}
}
int main()
{
int i=0,j=0,x=0,y=0,le=0;
int a[N][N];
for(i=0;i<N;i++)//賦值默認路徑長度max
{
for(j=0;j<N;j++)
{
a[i][j]=Max;
}
}
for(;x!=-1;)//手動賦權值
{
scanf("%d,%d,%d",&x,&y,&le);
a[x-1][y-1]=le;
a[y-1][x-1]=le;
}
a[0][0]=0;
node nd[N]={0};
for(i=0;i<N;i++)
{
nd[i].len=a[0][i];
}
dkstra(nd,a);
for(i=0;i<N;i++)
{
j=0;
printf("Node %d :\n best way : 1 ",i+1);
while(nd[i].way[j]!=0)
{
printf(" -> ");
printf("%d",nd[i].way[j]);
j++;
}
printf(" -> ");
printf("%d",i+1);
printf("\nminLength: %d\n",nd[i].len);
}
return 0;
}
測試用例:
測試結果:
問題,每一個i點都依賴於j點,用上述代碼的話,在得到前幾個點的minlen時,是否會出錯?
測試用例:測試結果:
發現,minlen[2]不正確。出現這種情況的原因是在找minlen[2]的時候,minlen[6]此時還是max,所以遍歷不出真正的最短路徑。這個時候我們再循環一次,由於后續的最短路徑已經找到,此時是不是可以找到真正的最短路徑呢?
代碼修改部分:
void dkstra(node nd[],int (*a)[N])
{
int i=0,j=0;
for(i=1;i<N;i++)
{
int tag=0;
for(j=0;j<N;j++)
{
if(nd[i].len<Max&&nd[j].len+a[j][i]<Max)
tag=1;
nd[i].len<=(nd[j].len+a[j][i])?(nd[i].len=nd[i].len):(nd[i].len=(nd[j].len+a[j][i]),addWay(&nd[i],j+1,tag));
tag=0;
}
}
for(i=1;i<N;i++)
{
int tag=0;
for(j=0;j<N;j++)
{
if(nd[i].len<Max&&nd[j].len+a[j][i]<Max)
tag=1;
nd[i].len<=(nd[j].len+a[j][i])?(nd[i].len=nd[i].len):(nd[i].len=(nd[j].len+a[j][i]),addWay(&nd[i],j+1,tag));
tag=0;
}
}
}
測試用例仍然是上面的圖,測試結果如下:
此時,最小路徑的數據基本正確,但是測試不多,暫時也不能確定代碼正確。而且由於addway()的原因,無法保存正確的路徑的結點信息。這些問題,等待進一步完善。