Dijkstra算法与实现--进阶篇
来源:互联网 发布:4g网络制式 编辑:程序博客网 时间:2024/05/16 14:39
1. 本文主要集中使用最小堆数据结构实现Dijkstra算法。
首先, 将前文IsInS结构拆分为vector<int> S, vector<int>Q, 方便最小堆的实现,S也是可以删除的,修改后的代码如下
#include <iostream> #include <iostream> #include <vector> #include <stack> #include<algorithm>#include "bheap.hpp"using namespace std; int map[][6] = { //定义无向图,或者有向图 {0, 6, 3, INT_MAX, INT_MAX, INT_MAX}, {6, 0, 2, 5,INT_MAX, INT_MAX}, {3, 2, 0, 3,4, INT_MAX}, {INT_MAX,5, 3, 0, 2, 3}, {INT_MAX,INT_MAX, 4, 2, 0, 5}, {INT_MAX,INT_MAX,INT_MAX,3,5,0}}; void init(int num, int startVertex,int distance[], int prevVertex[], vector<int>& Q){/*初始化distance和prevVertex数组*/ for(int i =0; i < num; ++i) { distance[ i ] = map[ startVertex ][ i ]; //源节点到各个节点的距离,其中INT_MAX代表不可达 if(map[ startVertex ][ i ] < INT_MAX) //如果是可达的 prevVertex[ i ] = startVertex; else prevVertex[ i ] = -1; //表示还不知道前一个节点是什么 } prevVertex[ startVertex ] = -1; //源节点无前一个节点 for(int i =0; i < num; ++i) { if(i != startVertex) { Q.push_back(i); } }}void extractMin(vector<int>& Q,int distance[],int& currentVertex){ /*在Q中选择u到j的distance最小的一个节点, 如第一步A到C,最后目标到D*/ int minDistance = INT_MAX; vector<int>::iterator ite = Q.begin(); for(; ite!=Q.end();ite++) // { if((distance[*ite] < minDistance))//寻找初始currentVertexA到Q中distance最小的节点 最后为新的currentVertexC { currentVertex = *ite; minDistance = distance[*ite]; } } return;}/*对这个新的currentVertexC做松弛计算,更新distance*/ void Relax(vector<int> Q,int distance[],int pre[],int& currentVertex){ vector<int>::iterator ite = Q.begin(); for(; ite!=Q.end();ite++) { if (map[currentVertex][*ite] < INT_MAX) //在Q中,有距离的为c->d,c->e, c->b { int currentdist = distance[ currentVertex] + map[ currentVertex ][*ite]; if (currentdist < distance[ *ite ]) //distance[j]为开始到j的距离 { distance[ *ite ] = currentdist; pre[ *ite] = currentVertex; } } } } void Dijkstra( const int numOfVertex, /*节点数目*/ const int startVertex, /*源节点*/ int (map)[][6], /*有向图邻接矩阵*/ int *distance, /*各个节点到达源节点的距离*/ int *prevVertex /*各个节点的前一个节点*/ ) { vector<int> Q; //step1 init(numOfVertex, startVertex,distance, prevVertex, Q); /*开始使用贪心思想循环处理不在S集合中的每一个节点*/ int currentVertex = startVertex; for (int i = 1; i < numOfVertex; i ++) //这里循环从1开始是因为开始节点已经存放在S中了,还有numOfVertex-1个节点要处理 { //step2 extractMin(Q,distance,currentVertex); //S.push_back(currentVertex); Q.erase(remove(Q.begin(),Q.end(),currentVertex),Q.end()); //step3 Relax(Q,distance,prevVertex,currentVertex); } } int main (int argc, const char * argv[]) { int distance[6]; int preVertex[6]; //for (int i =0 ; i < 5; ++i ) //源目标为i的 //{ Dijkstra(6, 0, map, distance, preVertex); //for(int j =0; j < 6; ++j) //{ int index = 5; //加上for目标为j的 stack<int > trace; while (preVertex[index] != -1) { trace.push(preVertex[index]); cout<<"push"<<preVertex[index]<<endl; index = preVertex[index]; } cout << "路径:"; while (!trace.empty()) { cout<<trace.top()<<" -- "; trace.pop(); } cout <<5; //j cout <<" 距离是:"<<distance[5]<<endl; //j // } //} system("pause"); return 0; }
2. 在先前的基本Dijkstra算法的实现中, extractMin()算法需要O(n)次操作才能找到最小值。所以修改为最小堆实现,算法效率变为O(logn)小根堆的实现可以参考前文。
Dijkstra 算法+Heap堆完整算法思想
在前一篇文章中,我们已经了解到,Dijkstra 算法如下:
DIJKSTRA(G, w, s)
1 INITIALIZE-SINGLE-SOURCE(G, s) //1、初始化结点工作
2 S ← Ø
3 Q ← V[G] //2、初始化队列
4 while Q ≠ Ø
5 do u ← EXTRACT-MIN(Q) //3、从最小队列中,抽取最小结点(在此之前,先建立最小堆)
6 S ← S ∪{u}
7 for each vertex v ∈ Adj[u]
8 do RELAX(u, v, w) //4、松弛操作。
实现代码如下:
3.1 头文件bheap.hpp
#include <vector> using namespace std; inline bool mincmp(const int &x, const int &y) { return x < y; } class DIST{public: int index; int dist; DIST() { index =0; dist = INT_MAX; } DIST& operator=( const DIST& d){ index = d.index; dist=d.dist; return *this;}};class minHeap { public: int n;//n表示当前Q中的元素个数 vector<DIST> Q;public: inline minHeap() { n=0; Q = vector<DIST>(6); } inline void push(DIST x)//插入操作,向上调整 ,将最后节点的值即即将插入的值和父节点比较 { int hole = n++;//(0-n) for(; hole > 0 && mincmp(x.dist, Q[hole >> 1].dist); hole = hole >> 1)//把这个元素和根节点比较并交换 { Q[hole] = Q[(hole) >> 1]; } Q[hole] = x; } inline void deletenode(int pos)//删除操作, 向下调整 ,将最后一个节点的值和子节点较优者比较交换 { int tmp;//(0-n-1) DIST value = Q[pos]; int hole = pos; int lc = (hole<<1)+1; while(lc+1 < n) { tmp = (mincmp(Q[lc+1].dist, Q[lc].dist) )? (lc+1) : lc; if(mincmp(Q[tmp].dist, Q[n-1].dist)) { Q[hole] = Q[tmp]; lc = (lc<<1)+1; //rc = lc+1; hole =tmp; } else { break; } } Q[hole] = Q[n-1]; //save n-1,这一步很重要,不然value会丢失 Q[n-1] =value; n--; } inline void pop()//弹出操作 { deletenode(0); } inline DIST top() { return Q[0]; }//返回堆顶元素 };
实现算法的文件
<p> </p><p>#include <iostream> #include <iostream> #include <vector> #include <stack> #include<algorithm>#include "bheap.hpp"using namespace std; int preVertex[6]; int map[][6] = { //定义无向图,或者有向图 {0, 6, 3, INT_MAX, INT_MAX, INT_MAX}, {6, 0, 2, 5,INT_MAX, INT_MAX}, {3, 2, 0, 3,4, INT_MAX}, {INT_MAX,5, 3, 0, 2, 3}, {INT_MAX,INT_MAX, 4, 2, 0, 5}, {INT_MAX,INT_MAX,INT_MAX,3,5,0}}; minHeap minh;void initMinHeap(int num, int startVertex){ for(int i =0; i < num; ++i) { DIST tempdist; tempdist.index = i; tempdist.dist = map[ startVertex ][ i ]; minh.push(tempdist); } vector<DIST>::iterator ite = minh.Q.begin(); //初始化堆Q BCDEF minh.pop();//弹出节点startVertex}void initPreVertex(int num, int startVertex){ for(int i =0; i<num;i++) { if(map[ startVertex ][ i ] < INT_MAX) //如果是可达的 preVertex[ i ] = startVertex; else preVertex[ i ] = -1; //表示还不知道前一个节点是什么 </p><p> } preVertex[ startVertex ] = -1; //源节点无前一个节点}void init(int num, int startVertex){ /*初始化distance和prevVertex数组*/ initMinHeap(num,startVertex); initPreVertex(num,startVertex);}/*对这个新的currentVertexC做松弛计算,更新distance*/ void Relax(DIST& d){ vector<DIST>::iterator ite = minh.Q.begin();//store Q int i =0; int predist = d.dist; int currentVertex = d.index; for(; ite!= minh.Q.end() && i<minh.n ;i++, ite++) //deal with data in Q, the first n nums { if (map[currentVertex][ite->index] < INT_MAX) //在Q中,有距离的为c->d,c->e, c->b { int currentdist = predist + map[ currentVertex ][ite->index]; if (currentdist < ite->dist) //distance[j]为开始到j的距离 { ite->dist = currentdist; preVertex[ite->index] = currentVertex; } } }} void Dijkstra( const int numOfVertex, /*节点数目*/ const int startVertex, /*源节点*/ int (map)[][6] /*有向图邻接矩阵*/ ) { //step1 init(numOfVertex, startVertex);//Q BCDEF /*开始使用贪心思想循环处理不在S集合中的每一个节点*/ int currentVertex = startVertex; //A for (int i = 1; i < numOfVertex; i ++) //这里循环从1开始是因为开始节点已经存放在S中了,还有numOfVertex-1个节点要处理 { //step2 DIST currentDist = minh.top();//extract min minh.pop(); Relax(currentDist); } } int main (int argc, const char * argv[]) { for (int i =0 ; i < 5; ++i ) //源目标为i的 { Dijkstra(6, i, map); for(int j =0; j < 6; ++j) { int index = j; //加上for目标为j的 stack<int > trace; while (preVertex[index] != -1) { trace.push(preVertex[index]); cout<<"push"<<preVertex[index]<<endl; index = preVertex[index]; } cout << "路径:"; while (!trace.empty()) { cout<<trace.top()<<" -- "; trace.pop(); } cout <<j; //j vector<DIST>::iterator ite = minh.Q.begin(); for(;ite!= minh.Q.end(); ite++) { if(ite->index == j) { cout <<" 距离是:"<<ite->dist<<endl; //j } } } } system("pause"); return 0; } </p><p> </p>
0 0
- Dijkstra算法与实现--进阶篇
- Dijkstra算法与实现--基础篇
- Dijkstra(迪杰斯特拉)算法分析与实现(C++)
- dijkstra Bellman_Ford与Floyd算法的性质比较与实现
- 第0篇--Dijkstra算法的实现
- Dijkstra算法的实现
- dijkstra算法实现
- Dijkstra算法(c++实现)
- Dijkstra算法(c++实现)
- Dijkstra算法实现
- Dijkstra算法实现
- Dijkstra算法C#实现
- Dijkstra算法 ---java实现
- dijkstra算法JAVA实现
- Dijkstra算法实现
- Java实现Dijkstra算法
- DIJKSTRA算法-java实现
- Dijkstra算法Java实现
- DOTNET中GC原理
- STL源码剖析——序列容器之list
- C++常见问题
- 3-3 构造函数的调用(高级)
- Listener中取Spring容器中Bean的实例
- Dijkstra算法与实现--进阶篇
- IPC链接
- 概率学统计与赌博的诡异问题
- 大数据量并发处理
- Java Field 详解
- 线程池ThreadPoolExecutor,Future
- Go基础 - slice
- Solr4.3数据异常分析
- android-修改TextView中部分文字的颜色