Programming Question-5-Dijkstra Algorithm via Min-Heap (including Notes)

In this programming problem you’ll code up Dijkstra’s shortest-path algorithm. 

Download the text file here. (Right click and save link as). 
The file contains an adjacency list representation of an undirected weighted graph with 200 vertices labeled 1 to 200. Each row consists of the node tuples that are adjacent to that particular vertex along with the length of that edge. For example, the 6th row has 6 as the first entry indicating that this row corresponds to the vertex labeled 6. The next entry of this row “141,8200” indicates that there is an edge between vertex 6 and vertex 141 that has length 8200. The rest of the pairs of this row indicate the other vertices adjacent to vertex 6 and the lengths of the corresponding edges.

Your task is to run Dijkstra’s shortest-path algorithm on this graph, using 1 (the first vertex) as the source vertex, and to compute the shortest-path distances between 1 and every other vertex of the graph. If there is no path between a vertex v and vertex 1, we’ll define the shortest-path distance between 1 and v to be 1000000. 

You should report the shortest-path distances to the following ten vertices, in order: 7,37,59,82,99,115,133,165,188,197. You should encode the distances as a comma-separated string of integers. So if you find that all ten of these vertices except 115 are at distance 1000 away from vertex 1 and 115 is 2000 distance away, then your answer should be 1000,1000,1000,1000,1000,2000,1000,1000,1000,1000. Remember the order of reporting DOES MATTER, and the string should be in the same order in which the above ten vertices are given. Please type your answer in the space provided.

IMPLEMENTATION NOTES: This graph is small enough that the straightforward O(mn) time implementation of Dijkstra’s algorithm should work fine. OPTIONAL: For those of you seeking an additional challenge, try implementing the heap-based version. Note this requires a heap that supports deletions, and you’ll probably need to maintain some kind of mapping between vertices and their positions in the heap.


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#define MAX 200

const char INFILE[]="dijkstraData.txt";
struct EDGE        {
  long vertex;
  long weight;
  struct EDGE *next;
};
void fetch_g(struct EDGE **g)        {
  FILE *fp = fopen(INFILE,"r");
  long i,v,w;
  char *token,line[800];
  struct EDGE *node;
  while (fgets(line,800,fp))        {
        token = strtok(line,"\t");        
        i = atoi(token);
        g[i] = malloc(sizeof(struct EDGE));
        g[i]->next = NULL;
        while (token = strtok(NULL,"\t\r\n"))        {
                sscanf(token,"%ld,%ld",&v,&w);
                node = malloc(sizeof(struct EDGE));
                node->vertex = v;
                node->weight = w;
                node->next = g[i]->next;
                g[i]->next = node;
        }
  }
}
void print_g(struct EDGE *g)        {
  struct EDGE *node;
  for (node=g; node->next; node=node->next)
        printf("%ld,%ld\t",node->next->vertex,node->next->weight);
  printf("\n");
}
void HEAP_DECREASE_KEY(long *q,long i,long *d)        {
  long tmp;
  while ((i>1) && (d[q[i/2]]>d[q[i]]))        {
        tmp = q[i];        q[i] = q[i/2]; q[i/2] = tmp;
        i = i/2;
  }
}
void INIT_SINGLE_SOURCE(struct EDGE **g,long s,long *d,long *p)        {
  long i;
  for (i=1; i<=MAX; i++)        {        
        d[i] = 1000000;                //        d[i] = INFINITY
        p[i] = -1;                        //        p[i] = NIL
  }
  d[s]=0;
}
void MIN_HEAPIFY(long *q,long i,long *d)        {
  long left = 2*i, right = 2*i+1, smaller, tmp;
  if ((left<=q[0])&&(q[left]<q[i]))
        smaller = left;
  else 
        smaller = i;
  if ((right<=q[0])&&(q[right]<q[smaller]))
        smaller = right;
  if (smaller != i)        {
        tmp = q[smaller]; q[smaller] = q[i]; q[i] = tmp;
        MIN_HEAPIFY(q,smaller,d);
  }
}
long EXTRACT_MIN(long *q, long *d)        {
  long min = q[1];
  q[1] = q[q[0]--];
  MIN_HEAPIFY(q,1,d);
  return min;
}
void REFRESH(long u,struct EDGE **g,long *d,long *p)        {
  struct EDGE *node;
  long v,w;
  for (node=g[u]; node->next; node=node->next)        {
        v = node->next->vertex;
        w = node->next->weight;
        if (d[u]+w<d[v])        {
          d[v]=d[u]+w;
          if (p[v]==(-1))        
                p[v]=u;
          else
                REFRESH(v,g,d,p);
        }
  }
}
void Dijkstra(struct EDGE **g, long s)        {
  long *d,*p,*q,i,u;
  struct EDGE *node;
  d = calloc(MAX+1,sizeof(long));
  p = calloc(MAX+1,sizeof(long));
  q = calloc(MAX+1,sizeof(long));
  q[0] = MAX;
  for (i=1; i<=MAX; i++)
        q[i] = i;
  INIT_SINGLE_SOURCE(g,s,d,p);
  while (q[0])        {
        u=EXTRACT_MIN(q,d);
        REFRESH(u,g,d,p);
  }
  printf("%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld\n",d[7],d[37],d[59],d[82],d[99],d[115],d[133],d[165],d[188],d[197]);
}
void main()
{
  struct EDGE **g;
  g = (struct EDGE **)calloc(MAX+1,sizeof(struct EDGE *));
  fetch_g(g);
  Dijkstra(g,1);
}

// My notes followed

Ref: http://blog.csdn.net/v_JULY_v/article/details/6274836# A very detailed blog. but I would rather do it myself.

Book: Introduction to Algorithms by CLRS

Suggested Readings:Chapter 6, Chapter 24 (section 3,4)

According to Ch 24.3 <Dijkstra Algorithm>

Dijkstra(G,w,s)
  INITIALIZATION_SINGLE_SOURCE(G,s);
  S<-NULL;
  Q<-V[G];
  while (Q)
    u<-EXTRACT_MIN(Q)
    S<-S+{u}
    for each vertex v in Adj[u]
        RELAX(u,v,w)


here, w means weight of the edge. Andw(u,v) >= 0 for each pari of vertices(u,v).

A vivid presentation of Dijkstra algorithm could be found on wikipedia.

Here the function INITIALIZATION_SINGLE_SOURCE(G,s) andRELAX(u,v,w) could be found in Ch 24.0.

For each vertex v, define d[v] as the upper bound on the weight of a shortest path from s to v, or a shortest-path estimate.

INITIALIZATION_SINGLE_SOURCE(G,s) for each vertex v in V[G] d[v] <- inifity p[v] <- null d[s]<-0

Here, p[v] means the predecessor. 

The process of relaxing an edge (u,v) consisting of testing whether we can improve the shortest path to v found so far by going through u and updatingd[v] andp[v]. It may decrease the value of the d[v] and update p[v].

RELAX(u,v,w) if d[v]>d[u]+w(u,v) d[v] <- d[u]+w(u,v) p[v] <- u


EXTRACT_MIN(Q) should goto the heap chapter, i.e. Chapter 6.

An efficient priority queue is one of the most popular applications of a heap. Chapter 6.5 <Priority queues>

A priority queue is a data structure for maintaining a set S of elements. A min-priority queue supports the operations INSERT,MINIMUM,EXTRACT_MIN, and DECREASE_KEY. 

A min-priority queue can be used in an event-driven simulator. The items in the queue are events to be simulated, each with an associated time of occurrence that serves as its key. The events must be simulated in order of their time of occurrence, because the simulation of an event can cause other events to be simulated in the future. The simulation program uses EXTRACT_MIN at each step to choose the next event to simulate. As new events are produced, they are inserted into the min_priority queue using INSERT.

When a heap is used to implement a priority queue, we often need to store ahandle to the corresponding application object in each heap element. Similarly, we need to store a handle to the corresponding heap element in each application object. 

The handle would typically be an array index.

Goto Chapter 6.1 <Heap>

An array A that represents a heap is an object with two attributes:length[A] andheap-size[A].A[1..length[A]].

The root of the tree is A[1].

PARENT(j) = j/2; LEFT(j) = 2j; RIGHT(j) = 2j+1;

A min-heap means A[PARENT(j)] <= A[j].

HEAP_EXTRACT_MIN(A)
  if heap-size[A] < 1
    error "heap underflow"
  min <- A[1]
  A[1] <- A[heap-size[A]]
  heap-size[A] = heap-size[A]-1
  MIN_HEAPIFY(A,1)
  return min

So, the function HEAP_EXTRACT_MIN(A) extract the root and replace root withA[heap-size[A]]. ThenMIN_HEAPIFY is called to keep the heap property of the array.

MIN_HEAPIFY(A,i) is a very important subroutine for manipulating min-heaps. It assumed that the binary trees rooted at LEFT(i) and RIGHT(i) are min-heaps. The function let the value at A[i] “float down” in the min-heap.

MIN_HEAPIFY(A,i)
  left<-LEFT(i)
  right<-RIGHT(i)
  if left<=heap-size[A] and A[left]<A[i]
    smaller <- left
  else 
    smaller <- i
  if right<=heap-size[A] and A[right]<A[smaller]
    smaller <- right
  if smaller!=i
    exchange (A[i], A[smaller])
    MIN_HEAPIFY(A,smaller)


Finally, a linked-list-array is used to store the weighted directed graph.

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/Gary_D_Shi/article/details/7764853
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞