双向Dijstra算法
2015-12-17 16:30
393 查看
双向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。
[code]
//使用二叉堆选择最小元素的双向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; }
相关文章推荐
- js中数组indexOf
- Gson解析Json数据
- ExtJS5 - 使用vtype自定义表单域的验证规则
- 【学习笔记javascript设计模式与开发实践(迭代器模式)----7】
- 判断JS对象是否拥有某属性的方法举例
- ExtJS5 - 编码规范
- [Servlet&JSP] JSTL的使用
- JVM监控工具:jps、jstat、jinfo、jmap、jhat、jstack使用介绍
- JavaScript判断数据类型
- ExtJS5 - 认识MVVM
- js中的double
- JSON介绍
- js获取网页高度(详细整理)
- 如何学习javascript
- JS 模板引擎 Handlebars.js 中文说明
- JavaScript数据类型
- JS订阅方法
- javascript对象之javascript数组
- JS实现alert中显示换行的方法
- Json序列化和反序列化之jackson