对于图的相关算法如最小生成树的Kruskal,Prim算法,最短路径的Dijkstra算法都采用的是贪心算法,而贪心算法最好的辅助工具个人认为就是priority_queue.所以本文将运用priority_queued对算法导论中Dijkstra算法进行优化。对于Dijkstra算法我们先给出算法导论中所给出基本算法实现。
int a[5][5] = {
{MAX2,10,MAX2,MAX2,5},
{MAX2,MAX2,1,MAX2,2},
{MAX2,MAX2,MAX2,4,MAX2},
{7,MAX2,6,MAX2,MAX2},
{MAX2,3,9,2,MAX2},
};
int distant[5] = {MAX2,MAX2,MAX2,MAX2,MAX2}; //标记距离
int visit[5] = {0}; //标记是否内访问
int temp = MAX2; //MAX2表示不可达
void Dijkstra(int start)
{
int i,j,k;
visit[start] = 1;
distant[start] = 0;
for(i = 0; i < 5; i++)
{ if(i!= start)
distant[i] = a[start][i];
}
for(i = 0; i < 5; i++)
{
temp = MAX2;
//*************algrithms****对应于算法导论中的EXTRACT-MIN(Q)********************
for(j = 0; j < 5; j++)
{
if(!visit[j] && temp > distant[j])
{
temp = distant[j];
k = j;
}
}
if(temp == MAX2) break;
visit[k] = 1;
//**********************算法导论中的RELAX(u,v,w)******************************
for(j = 0; j < 5; j++)
{
if(!visit[j] && distant[j] > distant[k] + a[k][j])
distant[j] = distant[k] + a[k][j];
}
//***************************************************
}
}
上述算法完全按照算法导论中伪代码翻译过来,并且注明了对应关系。下面我们使用优先队列来 优化该算法。完整代码如下(可以说是一种广度搜索算法):
#include<stdio.h>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define raw 5
#define col 5
#define MAX 0x0fffffff
struct node
{
int x; //表示对应的点
int parent; //上述代码没有给出具体的路径,在优化代码中我们使用该值存储,x的前去节点
int cost; //每次给句cost选出权值最小的点
};
struct cmp
{
bool operator()(struct node a, struct node b)
{
return a.cost > b.cost;
}
};
int map[raw][col] = { //算法导论中所给出图的关系矩阵
{ MAX, 10, MAX,MAX,5},
{ MAX, MAX, 1, MAX,2},
{ MAX,MAX,MAX, 4 ,MAX},
{ 7, MAX,6, MAX, MAX},
{MAX, 3, 9, 2 ,MAX}
};
int visit[raw]={0}; //标记该点有没有被访问过
int pre[raw] = {-1,-1,-1,-1,-1}; //展示前趋
void Dijkstra(int start_i, int end_i)
{
priority_queue<struct node, vector<struct node>, cmp> Queue;//优先队列
struct node in;
in.x = start_i;
in.cost = 0;
in.parent = -1;
Queue.push(in);
visit[start_i] = 1;
while(!Queue.empty())
{
int i;
int j;
struct node out = Queue.top(); //每次弹出cost最小的点
Queue.pop(); //弹出已选的点很重要,不然死循环
i = out.x;
pre[out.x] = out.parent; //标记前趋
visit[out.x] = 1; //标记该点已经被 选取
if(out.x == end_i)
{
printf("the min cost is %d\n", out.cost );
return ;
}
//下面代码实现将与i相连得节点入队列相当于算法导论中的松弛
for(j = 0; j < col; j++)
{
if(map[i][j] != MAX && !visit[j])
{
in.x = j;
in.parent = i;
in.cost = out.cost + map[i][j];
Queue.push(in);
}
}
}
}
int main()
{
Dijkstra(0,3);
int i;
i = 3;
while(pre[i] != -1)
{
printf(" %d pre is:%d\n",i, pre[i]);
i = pre[i];
}
}
总体来说运用优先队列代码比较简洁,而且有使用堆算法寻找最小的点lgn的复杂度,所以相对于上述算法效率较高。
下面给出一个实例:
有一辆坦克从一个位置到达另一个位置,有些位置需要2s,有些点需要1s先再给出起始点。问最少经过多少s到达目的地。这个可以归结为BFS算法与Dijkstra的结合(毕竟是找最短路径所以Dijkstra肯定合适)。具体大家可以参考下面这篇博客。http://blog.csdn.net/niushuai666/article/details/6674993