Dijkstra 之最小堆实现

    上一篇完成了朴素实现, 这次用堆完成。GO

 

    图参考上一篇, Dijkstra 之朴素实现, 这里从简。

     

 建堆其实比较简单, 看一下伪代码, 能够有效的理解算法的核心。

 BUILD-MAX-HEAP(A)

1  heap-size[A] ← length[A]
2   for i ← |_length[A]/2_| downto  1
3        do MIN-HEAPIFY(A, i)    

MIN-HEAPIFY的作用是保持堆的性质。

MIN-HEAPIFY(A, i)  
  1 l ← LEFT(i)
  2 r ← RIGHT(i)
  3  if l ≤ heap-size[A] and A[l] > A[i]
  4    then smallest ← l
  5     else smallest ← i
  6  if r ≤ heap-size[A] and A[r] > A[smallest]
  7    then smallest ← r
  8  if smallest ≠ i
  9    then exchange A[i] <-> A[smallest]

 10         MAX-HEAPIFY(A, smallest)  

 

 代码实现:

  1  // implement of Binary heap
  2 #include <stdio.h>
  3 #include <malloc.h>
  4 
  5  #define MAX_VERTEX_NUM    20
  6  #define INFINITY    65535
  7 
  8 typedef  int edgeType;
  9 
 10 typedef  struct ArcNode
 11 {
 12      int adjIndex;             //  顶点下标
 13     ArcNode *nextArc;  
 14     edgeType weight;
 15 }ArcNode;
 16 
 17 typedef  struct VNode
 18 {
 19     ArcNode* firstArc;
 20 }VNode, AdjList[MAX_VERTEX_NUM];
 21 
 22 typedef  struct
 23 {
 24     AdjList adjList;
 25      int vexNum;
 26      int edgeNum;
 27 }ALGraph;
 28 
 29 
 30  void initALGraph(ALGraph* Gp,  int cnt)
 31 {
 32     Gp->edgeNum =  0;
 33     Gp->vexNum = cnt;
 34 
 35      for ( int i =  0; i < cnt; i++)
 36     {
 37         Gp->adjList[i].firstArc = NULL;
 38     }
 39 }
 40 
 41  void insertArc(ALGraph* Gp,  int head,  int tail,  int w)
 42 {
 43     ArcNode* arcNodePt = (ArcNode*)malloc( sizeof( struct ArcNode));
 44      if (arcNodePt == NULL)
 45     {
 46          return;
 47     }
 48 
 49     arcNodePt->nextArc = NULL;
 50     arcNodePt->adjIndex = tail;
 51     arcNodePt->weight = w;
 52 
 53     ArcNode* tailPt = Gp->adjList[head].firstArc;
 54      if (tailPt == NULL)
 55     {
 56         Gp->adjList[head].firstArc = arcNodePt;
 57     }
 58      else
 59     {
 60          while (tailPt->nextArc != NULL)
 61         {
 62             tailPt = tailPt->nextArc;
 63         }
 64         tailPt->nextArc = arcNodePt;
 65     }
 66     Gp->edgeNum++;
 67 }
 68 
 69 
 70  void displayGraph(ALGraph G)
 71 {
 72     ArcNode* arcNodePt;
 73 
 74      for ( int i =  0; i < G.vexNum; i++)
 75     {
 76         arcNodePt = G.adjList[i].firstArc;
 77         printf( " vertex(%d):  ", i);
 78 
 79          while (arcNodePt != NULL)
 80         {
 81             printf( " ->%d(weight: %d) ", arcNodePt->adjIndex, arcNodePt->weight);
 82             arcNodePt = arcNodePt->nextArc;
 83         }
 84         printf( " \n ");
 85     }
 86 }
 87 
 88  void printRoute( int start,  int node,  int* pi)
 89 {
 90     printf( " %d ", node);
 91       do 
 92     {
 93          printf( " <-%d ", pi[node]);
 94         node = pi[node];
 95     } while (node != start);
 96 
 97 }
 98 
 99  int getEdgeWeight(ALGraph G,  int head,  int tail)
100 {
101     ArcNode* arcNodePt = G.adjList[head].firstArc;
102 
103      while (arcNodePt != NULL)
104     {
105          if (arcNodePt->adjIndex == tail)
106         {
107              return arcNodePt->weight;
108         }
109         arcNodePt = arcNodePt->nextArc;
110     }
111 
112      return INFINITY;
113 }
114 
115 
116  void minHeapify( int* Q,  int* d,  int i)
117 {
118      int l =  2 * i;
119      int r =  2 * i +  1;
120      int smallest = i;
121 
122      if (l <= Q[ 0] && d[Q[l]] < d[Q[i]])
123     {
124         smallest = l;
125     }
126 
127     
128      if (r <= Q[ 0] && d[Q[r]] < d[Q[smallest]])
129     {
130         smallest = r;
131     }
132 
133     printf( " smallest = %d\n ", smallest, i, l ,r);
134 
135      if (smallest != i)
136     {
137          int temp = Q[i];
138         Q[i] = Q[smallest];
139         Q[smallest] = temp;
140 
141         minHeapify(Q, d, smallest);
142     }
143 }
144 
145  int extractMin( int* Q,  int* d)
146 {
147      int min;
148     min = Q[ 1];
149     Q[ 1] = Q[Q[ 0]];
150     Q[ 0] = Q[ 0] -  1;
151 
152      return min;
153 }
154 
155  void buildMinHeap( int* Q,  int* d,  int start)
156 {
157      for ( int i = Q[ 0]/ 2; i >=  1; i--)
158     {
159         minHeapify(Q, d, i);
160     }
161 }
162 
163  void initSingleSource(ALGraph G,  int start,  int* di,  int* pi)
164 {
165      for ( int i =  0; i < G.vexNum; i++)
166     {
167         di[i] = INFINITY;
168         pi[i] =  0;
169     }
170 
171     ArcNode* arcNodePt = G.adjList[start].firstArc;
172      while (arcNodePt != NULL)
173     {
174         di[arcNodePt->adjIndex] = arcNodePt->weight;
175         arcNodePt = arcNodePt->nextArc;
176     }
177     
178     di[start] =  0;
179 }
180 
181 
182  void dijkstra(ALGraph G,  int start,  int* d,  int* pi,  int* Q)
183 {
184      int u, v;
185      int visit[MAX_VERTEX_NUM] = { 0};
186 
187     initSingleSource(G, start, d, pi);
188 
189     visit[start] =  1;
190 
191     Q[ 0] = G.vexNum;
192      for ( int i =  1; i <= Q[ 0]; i++)
193     {
194         Q[i] = i -  1;
195     }
196 
197     
198      while (Q[ 0] !=  0)
199     {
200         buildMinHeap(Q, d, start);
201 
202          //  在提取最小点后, 利用每次重新建堆来保持堆的性质。 正常做法是将最后一个结点放到空结点,做下潜操作,复杂度O(logN)。 
203           //  建堆复杂度O(N), 效率稍低一点。
204         u = extractMin(Q, d);
205 
206          if (u == start)
207         {
208              continue;
209         }
210 
211         printf( " extract min node: %d\n ", u);
212 
213         visit[u] =  1;
214         ArcNode* arcNodePt = G.adjList[u].firstArc;
215          while (arcNodePt != NULL)
216         {
217             v = arcNodePt->adjIndex;
218             printf( " adjacent to : %d, d[v]=%d, d[u]=%d, w(u,v)=%d\n ", v, d[v], d[u], getEdgeWeight(G, u, v));
219 
220              //  松弛操作
221              if (!visit[v] && (d[v] > d[u] + getEdgeWeight(G, u, v)))
222             {
223                 d[v] = d[u] + getEdgeWeight(G, u, v);
224                 printf( " update d[%d]=%d\n ", v, d[v]);
225                 pi[v] = u;
226                 printf( " pi[%d]=%d\n\n ", v, pi[v]);
227             }
228             arcNodePt = arcNodePt->nextArc;
229         }
230 
231     }
232 
233         
234 
235     
236     
237 }
238 
239 
240  int main( int argc,  char  const *argv[])
241 {
242      #define startpoint 0
243     ALGraph G;
244     ALGraph* Gp = &G;
245 
246     initALGraph(Gp,  5);
247     insertArc(Gp,  0110);
248     insertArc(Gp,  035);
249     insertArc(Gp,  121);
250     insertArc(Gp,  132);
251     insertArc(Gp,  244);
252     insertArc(Gp,  313);
253     insertArc(Gp,  329);
254     insertArc(Gp,  342);
255     insertArc(Gp,  426);
256     insertArc(Gp,  407);
257 
258     printf( " print the graph: \n ");
259     displayGraph(G);
260 
261      int d[MAX_VERTEX_NUM];
262      int pi[MAX_VERTEX_NUM];
263      int Q[MAX_VERTEX_NUM +  1];    //  Q[0]保存个数
264 
265 
266     dijkstra(G, startpoint, d, pi, Q);
267 
268      for ( int i =  0; i < G.vexNum; i++)
269     {
270         printf( " From %d to %d length is %d. \n ", startpoint, i, d[i]);
271         printf( " Path : ");
272 
273         printRoute(startpoint, i, pi);
274         printf( " \n ");
275     }
276 
277      return  0;
278 }
View Code

 

   本来还想用二项堆和斐波那契堆都实现一下, 看了下有点复杂, 没有太大必要。 后面再说。

   关于上面的实现还想说一点, 注释也有说明, 在每次提取最小节点和松弛操作后, 利用重新建堆的方法重新保持堆的性质, 复杂度O(N)。 还有另外一种做法是只建一次堆, 然后在提取最小节点后,马上做调整, 复杂度O(logN). 并在每次松弛操作后, 由于节点的d[v]减小, 需要沿着树枝向上做更新操作, 以保持堆的性质。平均复杂度应该是小于O(logN)的, 这种方法的优点就是性能稍好, 不过就是有点麻烦。

 

 

 

 
 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/freedreamnight/p/3734549.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值