最短路径—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");
}
#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/
- 最短路径算法——Dijkstra
- 最短路径——Dijkstra算法
- 最短路径——Dijkstra算法
- 最短路径—Dijkstra算法
- 最短路径Ⅰ—Dijkstra算法
- 最短路径—Dijkstra算法
- 最短路径算法—Dijkstra(迪杰斯特拉)
- 最短路径—Dijkstra算法
- 最短路径—Dijkstra算法
- 最短路径—Dijkstra算法
- Dijkstra — 最短路径算法
- 最短路径—Dijkstra算法
- 最短路径—Dijkstra算法
- 最短路径算法—Dijkstra(迪杰斯特拉)
- 最短路径—Dijkstra算法
- 最短路径—Dijkstra算法
- DIJKSTRA最短路径算法
- 最短路径算法-dijkstra
- FolderBrowserDialog(文件夹浏览对话框)
- iPhoneで繰り返しループするサウンドを鳴らすコードのメモ (Audio Queueのサンプル)
- BP神经网络算法学习
- IP ICMP TCP UDP 校验和
- ora-01261:参数db_recovery_file_dest的目标字符串无法被翻译
- 最短路径—Dijkstra算法
- C# 轻松获取路径中文件名、目录、扩展名等
- 谈谈C 运行库中的安全字符串函数
- Audio Queue Services
- C#操作zip压缩解压
- windowsXP的简单安全设置[原创]--菜鸟必读
- MyEclipse 里面怎么查看当前方法在哪儿被调用
- 关于c++中函数的返回值
- jQuery 简单实现无刷新select二级联动