双向Dijstra算法:在无向带权图中,求从s到t最短路径。双向Dijstra算法的思想是:分别从s顶点和t顶点开始执行单向Dijstra算法,从s点开始执行的Dijstra算法定义为前向Dijstra搜索,从t点开始执行Dijstra算法定义为后向Dijstra搜索。算法结束的条件是:前向(后向)Dijstra搜索求得当前最短路径上的顶点为u,且在后向(前向)Dijstra搜索已经计算出到u的最短路径,此时s到t的最短路径可以表示为sp(s,u)+sp(t,u)。
如图所示:求s到t的最短路径,我们分别从s和t执行Dijstra搜索,经过三次迭代后,前向(后向)Dijstra搜索已经求得最短路径上的点为s,a,b(t,g,f),此时优先队列Qf(执行前向Dijstra搜索使用的优先队列)和Qb(执行后向Dijstra搜索使用的优先队列)中分别存储c,d和e,d,且此时s到c和d的最短距离分别为6,10;t到e和d的最短距离也分别为6,10。继续执行,前向Dijstra搜索中c顶点执行出栈操作,同时松弛(c,e)和(c,d)边;后向Dijstra搜索中e顶点出栈,同时松弛(e,c)和(e,d)边。再一次迭代时,前向Dijstra搜索中e顶点执行出栈操作时,后向Dijstra搜索中已经求得t到e最短距离,所以双向Dijstra算法结束,最后求得s到t的最短距离为sp(s,e)+sp(t,e)=13。![双向Dijstra算法_第1张图片](http://img.e-com-net.com/image/info5/e4d0828bdfef4b1c9be65cd285cb0e34.jpg)
//使用二叉堆选择最小元素的双向Dijstra算法
#include<iostream>
#include<vector>
#include<fstream>
#include<time.h>
using namespace std;
//优先队列里存储元素类型
struct Node
{
int ver;//源点可达的顶点
int dis;//源点到可达顶点的距离
Node(){}
Node(int ver, int dis)
{
this->ver = ver;
this->dis = dis;
}
};
//优先队列类
struct HeapMin
{
vector<Node> ve;//优先队列中存储元素的容器
vector<int> index;//顶点在优先队列中的下标index[2] = 3;表示顶点为2的顶点存储在优先队列的3号位置。
int size;//优先队列的总容量
int cur;//当前优先队列中元素的个数
//初始化优先队列
HeapMin(int size)
{
this->size = size;
ve.resize(size);
index.resize(size);
cur = 0;
}
//优先队列中的某个位置(pos)的元素值被改变了,重新调整优先队列
void siftUp(int pos)
{
while(pos > 0 && ve[pos].dis < ve[(pos - 1)/2].dis)
{
swap(index[ve[pos].ver],index[ve[(pos - 1)/2].ver]);
swap(ve[pos],ve[(pos - 1)/2]);
pos = (pos - 1)/2;
}
}
//判断优先队列是否为空
bool empty()
{
if(cur == 0)
return true;
else
return false;
}
//返回优先队列中的最小元素但是不弹出
Node top()
{
return ve[0];
}
//弹出优先队列对头元素
void pop()
{
cur--;
swap(index[ve[cur].ver],index[ve[0].ver]);
swap(ve[0],ve[cur]);
siftDown(0);
}
//从当前位置开始向下调整优先队列
void siftDown(int start)
{
int i = start;
while((2 * i + 1) < cur && (2 * i + 2) < cur)
{
if(ve[2 * i + 1].dis < ve[2 * i + 2].dis)
{
if(ve[i].dis > ve[2 * i + 1].dis)
{
index[ve[2 *i + 1].ver] = i;
index[ve[i].ver] = 2 * i + 1;
swap(ve[i],ve[2 * i + 1]);
i = 2 * i + 1;
}
else
{
break;
}
}
else
{
if(ve[i].dis > ve[2 *i + 2].dis)
{
index[ve[2 * i + 2].ver] = i;
index[ve[i].ver] = 2 * i + 2;
swap(ve[i],ve[2 * i + 2]);
i = 2 * i + 2;
}
else
{
break;
}
}
}
if((2 * i + 1) < cur && ve[i].dis > ve[2 * i + 1].dis)
{
swap(ve[i],ve[2 * i + 1]);
index[ve[2 * i + i].ver] = i;
index[ve[i].ver] = 2 * i + 1;
}
}
//创建一个优先队列
void createHeap()
{
for(int i = cur / 2 - 1; i >= 0; --i)
{
siftDown(i);
}
}
//向优先队列中插入元素,但是不调整优先队列
void insert(int v, int w)
{
Node tmp(v,w);
ve[cur] = tmp;
index[cur++] = v;
}
};
//边的类型
struct Edge
{
int value;
float weight;
Edge(){}
Edge(int value,float weight)
{
this->value = value;
this->weight = weight;
}
};
vector<vector<Edge>> mGraph;//图结构
int nodeNum;//图中顶点数
int edgeNum;//图中边数
vector<int> df;//源点到当前顶点的距离
vector<int> db;
vector<int> flagf;
vector<int> flagb;
vector<int> p;//最短路径中的前一个顶点
HeapMin quf(10);//创建一个优先队列
HeapMin qub(10);
//读取图文件
void readGraph()
{
fstream fin("E:\\SPData\\data05.txt");//打开文件
fin>>nodeNum>>edgeNum;//读取顶点数和边数
mGraph.resize(nodeNum);
df.resize(nodeNum);
db.resize(nodeNum);
flagf.resize(nodeNum);
flagb.resize(nodeNum);
p.resize(nodeNum);
int id ,s , t;
float w;
Edge tmp;
while(fin>>id>>s>>t>>w)
{
tmp.value = t;
tmp.weight = w;
mGraph[s].push_back(tmp);
tmp.value = s;
tmp.weight = w;
mGraph[t].push_back(tmp);
}
fin.close();
}
//初始化源点到其他顶点的距离,并且初始化通过那个顶点到达这个顶点
void initialize_signal_source(int s,int t)
{
for(int i = 0; i < nodeNum; ++i)
{
db[i] = 1000;//设置为无穷(用1000表示)
df[i] = 1000;
flagf[i] = 0;
flagb[i] = 0;
p[i] = -1;
}
flagf[s] = 1;
flagb[t] = 1;
df[s] = 0;
db[t] = 0;
}
//松弛边的操作
void relaxf(int u, int v, int w)
{
if(flagf[v] != 2 && df[v] > df[u] + w)
{
df[v] = df[u] + w;
p[v] = u;
flagf[v] = 1;
int pos = quf.index[v];//得到要修改优先队列中距离值得下标
quf.ve[pos].dis = df[u] + w;//修改对应优先队列中距离值
quf.siftUp(pos);//从新调整优先队列
}
}
void relaxb(int u, int v, int w)
{
if(flagb[v] != 2 && db[v] > db[u] + w)
{
db[v] = db[u] + w;
p[v] = u;
flagb[v] = 1;
int pos = qub.index[v];//得到要修改优先队列中距离值得下标
qub.ve[pos].dis = db[u] + w;//修改对应优先队列中距离值
qub.siftUp(pos);//从新调整优先队列
}
}
//迪杰斯特拉算法
void dijkstra(int s,int t)
{
int dis = 0;
initialize_signal_source(s,t);//初始化
for(int i = 0; i < nodeNum; ++i)
{
quf.insert(i,df[i]);
qub.insert(i,db[i]);
}
quf.createHeap();//创建优先队列
qub.createHeap();
while(!quf.empty() && !qub.empty())//判断优先队列是否为空
{
int valf = quf.top().ver;//返回最小值
int valb = qub.top().ver;
if(flagb[valf] == 2)
{
dis = df[valf] + db[valf];
break;
}
if(flagf[valb] == 2)
{
dis = df[valb] + db[valb];
break;
}
flagf[valf] = 2;
flagb[valb] = 2;
quf.pop();//队头元素出队列
qub.pop();
int countf = mGraph[valf].size();
for(int i = 0; i < countf; ++i)
{
int u = valf;
int v = mGraph[valf][i].value;
int weight = mGraph[valf][i].weight;
relaxf(u,v,weight);
}
int countb = mGraph[valb].size();
for(int i = 0; i < countb; ++i)
{
int u = valb;
int v = mGraph[valb][i].value;
int weight = mGraph[valb][i].weight;
relaxb(u,v,weight);
}
}
cout<<dis<<endl;
}
int main(void)
{
readGraph();
dijkstra(0,8);
end = clock();
system("pause");
return 0;
}