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
原创粉丝点击