最短路径—Dijkstra算法

来源:互联网 发布:php 转成隐藏域 编辑:程序博客网 时间:2024/05/03 21:47
Dijkstra算法 
        Dijkstra算法是典型最短路算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。 

算法思想:
        设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将顶点加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

算法具体步骤:
    (1)初始时,S只包含源点,即S=v,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中。

算法举例说明:
        如下图,设A为源点,求A到其他各顶点(B、C、D、E、F)的最短路径。线上所标注为相邻线段之间的距离,即权值。(注:此图为随意所画,其相邻顶点间的距离与图中的目视长度不能一一对等)
    图一 :

 

 
算法执行过程如下表:


C++源代码:
#include<iostream>
#define MAX 200
#define Infinity 65535
using namespace std;

//边尾节点信息结构体
struct edgeNode
{
int no;   //尾接点序号
int cost;  //边权值
edgeNode *next; //其下一条邻接边尾节点指针
};

//节点信息结构体
struct vexNode
{
char info;  //节点名称
edgeNode *link; //与其相连的边的尾节点链表指针
};

struct Queue
{
int no; //队列中节点序号
int cost; //以此为尾节点的边的权值
};

//优先队列
Queue priQue[MAX];

//节点数组
vexNode adjlist[MAX];

//指定源点到节点i的最短路径花费
int lowcost[MAX];

//指定源点到节点i路径中,节点i的前驱节点序号
int parent[MAX];

//建立图邻接表
void createGraph(vexNode *adjlist,int *parent,int * lowcost,const int n,const int e)
{
int i;
for(i=1;i<=n;i++)
{
cout<<"请输入节点"<<i<<"的名称:";
cin>>adjlist[i].info;
adjlist[i].link = NULL;
lowcost[i] = Infinity;
parent[i] = i;
}
edgeNode *p1;
int v1,v2;
for(i=1;i<=e;i++)
{
cout<<"请输入边"<<i<<"的起始节点与尾节点序号:";
cin>>v1>>v2;
p1 = (edgeNode*)malloc(sizeof(edgeNode));
p1->no = v2;
cout<<"此边的权值:";
cin>>p1->cost;
p1->next = adjlist[v1].link;
adjlist[v1].link = p1;
}
}

//当插入节点到优先队列时,保持队列优先性
void keep_min_heap(Queue *priQue,int &num,const int k)
{
int l = 2*k;
int r = 2*k + 1;
int smallest = k;
if(l<=num&&priQue[l].cost<priQue[k].cost)
smallest = l;
if(r<=num&&priQue[r].cost<priQue[smallest].cost)
smallest = r;
if(smallest != k)
{
Queue temp = priQue[smallest];
priQue[smallest] = priQue[k];
priQue[k] = temp;
keep_min_heap(priQue,num,smallest);
}
}

//插入节点到优先队列时并且保持队列优先性
void heap_insert(Queue *priQue,int &num,int no,int cost)
{
num +=1;
priQue[num].no = no;
priQue[num].cost = cost;
int i = num;
while(i>1&&priQue[i/2].cost>priQue[i].cost)
{
Queue temp = priQue[i];
priQue[i] = priQue[i/2];
priQue[i/2] = temp;
i = i/2;
}
}

//取出优先队列的队头元素
Queue heap_extract_min(Queue *priQue,int &num)
{
if(num<1)
return priQue[0];

Queue min = priQue[1];
priQue[1] = priQue[num];
num -=1;
keep_min_heap(priQue,num,1);
return min;
}

//打印指定源点带序号为i的点的最短路径
void print_it(int *parent,vexNode *adjlist,int v)
{
if(parent[v] == v)
cout<<"("<<v<<":"<<adjlist[v].info<<") ";
else
{
print_it(parent,adjlist,parent[v]);
cout<<"("<<v<<":"<<adjlist[v].info<<") ";
}
}

void main()
{
int cases;
cout<<"请输入案例的个数:";
cin>>cases;
while(cases--)
{
int n,e;
cout<<"请输入节点数:";
cin>>n;
cout<<"请输入边数:";
cin>>e;
//队列中的元素,初始为0
int num = 0;
int i;
//创建邻接表
createGraph(adjlist,parent,lowcost,n,e);
cout<<endl;
cout<<"从哪个节点开始:";
int v0;
cin>>v0;
int v =v0;
lowcost[v0] = 0;
cout<<endl;
Queue queue;
for(i=1;i<n;i++)
{
edgeNode *p = adjlist[v0].link;
while(p != NULL)
{
if(lowcost[v0] + p->cost<lowcost[p->no])
{
lowcost[p->no] = lowcost[v0] + p->cost;
parent[p->no] = v0;
heap_insert(priQue,num,p->no,lowcost[p->no]);
}
p = p->next;
}
queue = heap_extract_min(priQue,num);
v0 = queue.no;
}

for(i=1;i<=n;i++)
{
  int mincost = 0;
  cout<<"从点"<<adjlist[v].info<<"开始到"<<adjlist[i].info<<"的最短路径为:"<<endl;
  print_it(parent,adjlist,i);
  cout<<endl;
  cout<<"距离为:"<<lowcost[i]<<endl;
}
}
system("pause");
}

请输入案例的个数:1

请输入节点数:5

请输入边数:10

请输入节点1的名称:a

请输入节点2的名称:b

请输入节点3的名称:c

请输入节点4的名称:d

请输入节点5的名称:e

请输入边1的起始节点与尾节点序号:1 2

此边的权值:10

请输入边2的起始节点与尾节点序号:1 4

此边的权值:5

请输入边3的起始节点与尾节点序号:2 3

此边的权值:1

请输入边4的起始节点与尾节点序号:2 4

此边的权值:2

请输入边5的起始节点与尾节点序号:3 5

此边的权值:4

请输入边6的起始节点与尾节点序号:4 2

此边的权值:3

请输入边7的起始节点与尾节点序号:4 3

此边的权值:9

请输入边8的起始节点与尾节点序号:4 5

此边的权值:2

请输入边9的起始节点与尾节点序号:5 1

此边的权值:7

请输入边10的起始节点与尾节点序号:5 3

此边的权值:6

从哪个节点开始:1

从点a开始到a的最短路径为:

(1:a)

距离为:0

从点a开始到b的最短路径为:

(1:a) (4:d) (2:b)

距离为:8

从点a开始到c的最短路径为:

(1:a) (4:d) (2:b) (3:c)

距离为:9

从点a开始到d的最短路径为:

(1:a) (4:d)

距离为:5

从点a开始到e的最短路径为:

(1:a) (4:d) (5:e)

距离为:7

请按任意键继续. .


参考转载:
【1】http://www.2cto.com/kf/201111/110578.html
【2】http://2728green-rock.blog.163.com/blog/static/43636790200901211848284/

原创粉丝点击