1. 程式人生 > >Dijkstra演算法(一個節點到其他所有節點的最短路徑)

Dijkstra演算法(一個節點到其他所有節點的最短路徑)

Dijkstra(迪傑斯特拉)演算法是典型的單源最短路徑演算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴充套件,直到擴充套件到終點為止。Dijkstra演算法是很有代表性的最短路徑演算法,在很多專業課程中都作為基本內容有詳細的介紹,如資料結構,圖論,運籌學等等。注意該演算法要求圖中不存在負權邊。

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

演算法思想:設G=(V,E)是一個帶權有向圖,把圖中頂點集合V分成兩組,第一組為已求出最短路徑的頂點集合(用S表示,初始時S中只有一個源點,以後每求得一條最短路徑 , 就將加入到集合S中,直到全部頂點都加入到S中,演算法就結束了),第二組為其餘未確定最短路徑的頂點集合(用U表示),

按最短路徑長度的遞增次序依次把第二組的頂點加入S中。在加入的過程中,總保持從源點v到S中各頂點的最短路徑長度不大於從源點v到U中任何頂點的最短路徑長度。此外,每個頂點對應一個距離,S中的頂點的距離就是從v到此頂點的最短路徑長度,U中的頂點的距離,是從v到此頂點只包括S中的頂點為中間頂點的當前最短路徑長度。

演算法步驟:

a.初始時,S只包含源點,即S={v},v的距離為0。U包含除v外的其他頂點,即:U={其餘頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。

b.從U中選取一個距離v最小的頂點k,把k,加入S中(該選定的距離就是v到k的最短路徑長度)。

c.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。

d.重複步驟b和c直到所有頂點都包含在S中。

說來慚愧,雖然上學期就學了資料結構,今天卻是第一次寫Dijkstra演算法,為了理解方便,註釋也照著書敲了一遍。
#include <stdio.h>
#include <stdlib.h>
#define MAXV 100
#define INF 999999
typedef struct{
int edges[MAXV][MAXV];//鄰接矩陣的邊陣列
int n,e;//頂點數,邊數
}MGraph;//完整的圖鄰接矩陣型別
void Dispath(MGraph g,int dist[],int path[],int s[],int v);
void Dijkstra(MGraph g,int v)
{
    int dist[MAXV];//dist[i]儲存從源點到i的目前的最短路徑長度
    int path[MAXV];//path[i]儲存當前最短路徑中的前一個頂點的編號
    int s[MAXV];//標記已找到最短路徑的頂點,s[i]=0表示未找到,s[i]=1表示已找到。
    int mindis,i,j,u;
    for(i=0;i<g.n;i++)
    {
        dist[i]=g.edges[v][i];//距離初始化
        s[i]=0;//s[ ]置空
        if(g.edges[v][i]<INF)//路徑初始化
            path[i]=v;//頂點v到頂點i有邊時,置頂點i的前一個頂點為v
        else
            path[i]=-1;//頂點v到頂點i沒有邊時,置頂點i的前一個頂點為-1
    }
    s[v]=1;//源點編號v放入s中
    path[v]=0;
    for(i=0;i<g.n;i++)//迴圈直到所有頂點的最短路徑都求出
    {
        mindis=INF;//mindis置最小長度初值為無窮大
        u=-1;
        for(j=0;j<g.n;j++)
            if(s[j]==0&&dist[j]<mindis)//選取不在s[]中且具有最小距離的頂點u
        {
            u=j;
            mindis=dist[j];
        }
        s[u]=1;//頂點u加入s
        for(j=0;j<g.n;j++)//修改不在s中的頂點的距離
            if(s[j]==0)
            if(g.edges[u][j]<INF&&dist[u]+g.edges[u][j]<dist[j])
        {
            dist[j]=dist[u]+g.edges[u][j];
            path[j]=u;
        }
    }
    Dispath(g,dist,path,s,v);
}
void Dispath(MGraph g,int dist[],int path[],int s[],int v)
{
    int i,j,k;
    int apath[MAXV],d;//存放一條最短路徑(逆向)及其頂點個數
    for(i=0;i<g.n;i++)
        if(s[i]==1&&i!=v)
    {
        printf("從頂點%d到頂點%d的路徑長度為:%d\t路徑為:",v,i,dist[i]);
        d=0,apath[d]=i;//新增路徑上的終點
        k=path[i];
        if(k==-1)//沒有路徑的情況
            printf("無路徑\n");
        else//存在路徑時輸出該路徑
        {
            while(k!=v)
            {
                d++;
                apath[d]=k;
                k=path[k];
            }
            d++;
            apath[d]=v;//新增路徑上的起點
            printf(" %d",apath[d]);//先輸出起點
            for(j=d-1;j>=0;j--)//再輸出其他頂點
                printf(",%d",apath[j]);
            printf("\n");
        }
    }
}
void DispMat(MGraph g)
//輸出鄰接矩陣g
{
	int i,j;
	for (i=0;i<g.n;i++)
	{
		for (j=0;j<g.n;j++)
			if (g.edges[i][j]==INF)
				printf("%3s","∞");
			else
				printf("%3d",g.edges[i][j]);
		printf("\n");
	}
}
int main()
{
	int i,j,u=0;
	MGraph g;
	int A[MAXV][6]={
		{0,5,INF,7,INF,INF},
		{INF,0,4,INF,INF,INF},
		{8,INF,0,INF,INF,9},
		{INF,INF,5,0,INF,6},
		{INF,INF,INF,5,0,INF},
		{3,INF,INF,INF,1,0}};
	g.n=6;g.e=10;
	for(i=0;i<g.n;i++)
		for (j=0;j<g.n;j++)
			g.edges[i][j]=A[i][j];
	printf("有向圖G的鄰接矩陣:\n");
	DispMat(g);
	Dijkstra(g,u);
	printf("\n");
}


原諒我只會用畫圖工具畫圖,有大佬可以告訴我下比較好用的畫這種圖的工具。