【428】Dijkstra 算法

算法思想:(单源最短路径)

  • 1个点到所有其他点的最短路径
  • 查找顶点到其他顶点的最短路径,无法到达的记为+∞,找到最小的,就找到了最短路径的顶点
  • 查看上一轮找到的最小点到达其他点的最小值,找到最短路径的顶点。
  • 以此类推
  • trivial relax:无穷大 ==> 具体数字
  • non-trival relax:具体数字 ==> 具体数

参考:https://www.bilibili.com/video/av36886088


 

运行效果:

step = 1, minw = 0, pacost[0] = 0.00
    trival relax: pacost[1] = inf ==> 1.00
    trival relax: pacost[3] = inf ==> 2.00

step = 2, minw = 1, pacost[1] = 1.00
    trival relax: pacost[2] = inf ==> 4.00

step = 3, minw = 3, pacost[3] = 2.00
    trival relax: pacost[2] = 4.00 ==> 3.00

step = 4, minw = 2, pacost[2] = 3.00

visited: {1, 1, 1, 1}
parent: {-1, 0, 3, 0}
pacost: {0.00, 1.00, 3.00, 2.00}

代码:

 Dijkstra.c 

#include <stdio.h>
#include <stdlib.h>

#include "WeGraph.h"

void DijkstraPrim(Graph g, int nV, int nE, Vertex src, char alg);

int main(){
	Graph g = newGraph(4);
	Edge e = newEdge(0, 1, 1);
	insertEdge(e, g);
	
	e = newEdge(1, 2, 3);
	insertEdge(e, g);
	
	e = newEdge(2, 3, 1);
	insertEdge(e, g);
	
	e = newEdge(3, 0, 2);
	insertEdge(e, g);
	
	DijkstraPrim(g, 4, 4, 0, 'd');
	
	return 0;
}

int *mallocArray(int numV) {               
	int *array = malloc(numV * sizeof(int));// l
	if (array == NULL) {                    // o
		fprintf(stderr, "Out of memory
");  // c
		exit(1);                             // a
	}                                       // l
	int i;                                  // f
	for (i=0; i<numV; i++) {                // u
		array[i] = UNVISITED;                // n
	}                                       // c
	return array;                           // t
} 

float *mallocFArray(int numV) {               
	float *array = malloc(numV * sizeof(float));// l
	if (array == NULL) {                    // o
		fprintf(stderr, "Out of memory
");  // c
		exit(1);                             // a
	}                                       // l
	int i;                                  // f
	for (i=0; i<numV; i++) {                // u
		array[i] = MAXWEIGHT;                // n
	}                                       // c
	return array;                           // t
} 

void showArray(char *desc, int *array, int numV) {
	int i;                                  // l
	printf("%s: {", desc);                   // o
	for (i=0; i<numV; i++) {                // c
		printf("%d", array[i]);              // a
		if (i <= numV-2) {                   // l
			printf(", ");                     // f
		}                                    // u
	}                                       // n
	printf("}
");                          // c
	return;                                 // t
}

void showFArray(char *desc, float *array, int numV) {
	int i;                                  // l
	printf("%s: {", desc);                   // o
	for (i=0; i<numV; i++) {                // c
		printf("%0.2f", array[i]);              // a
		if (i <= numV-2) {                   // l
			printf(", ");                     // f
		}                                    // u
	}                                       // n
	printf("}
");                          // c
	return;                                 // t
}

void DijkstraPrim(Graph g, int nV, int nE, Vertex src, char alg) {
// the last parameter arg is set by main, and is:
// 'd' for Dijkstra or
// 'p' for Prim

   int *visited = mallocArray(nV);   // initialised to UNVISITED
   int *parent = mallocArray(nV);    // initialised to UNVISITED
   float *pacost = mallocFArray(nV); // floats: initialised to INFINITY

   pacost[src] = 0.0;
   for (int step = 1; step <= nV; step++) {
   
   	  printf ("
step = %d, ", step);
   	  
      Vertex minw = -1;
      for (Vertex w = 0; w < nV; w++) {        // find minimum cost vertex
         if ((visited[w] == UNVISITED) &&
             (minw == -1 || pacost[w] < pacost[minw])) {
            minw = w;
         }
      }
      
      printf ("minw = %d, ", minw);
	  printf ("pacost[%d] = %0.2f
", minw, pacost[minw]);
	  
      visited[minw] = VISITED;

      for (Vertex w = 0; w < nV; w++) {         // 
         Weight minCost = getWeight(g, minw, w);// if minw == w, minCost = NOWEIGHT 
         // minCost is cost of the minimum crossing edge
         if (minCost != NOWEIGHT) {
            if (alg == 'd') {                   // if DIJKSTRA ...
               minCost = minCost + pacost[minw];// add in the path cost 
            }
            if ((visited[w] != VISITED) &&
                (minCost < pacost[w])) {
                   printf ("    trival relax: pacost[%d] = %0.2f ", w, pacost[w]);
                
                   pacost[w] = minCost;
                   parent[w] = minw;
                   
                   printf ("==> %0.2f
", pacost[w]);
            }
         }
      }
      
      
      
   }
   
   printf("
");
   
   showArray("visited", visited, nV);
   showArray("parent", parent, nV);
   showFArray("pacost", pacost, nV);
   free(visited);
   free(parent);
   free(pacost);
   return;
}

 WeGraph.c  

// WeGraph.c: an adjacency matrix implementation of a weighted graph
#include <stdio.h>
#include <stdlib.h>
#include "WeGraph.h"

struct graphRep { 
    int nV;       // #vertices 
    int nE;       // #edges 
    Weight **edges;  // matrix of weights
};

Graph newGraph(int numVertices) { 
    Graph g = NULL;
    if (numVertices < 0) {
       fprintf(stderr, "newgraph: invalid number of vertices
");
    }
    else {
        g = malloc(sizeof(struct graphRep)); 
        if (g == NULL) {
            fprintf(stderr, "newGraph: out of memory
");
            exit(1);
        }
        g->edges = malloc(numVertices * sizeof(int *)); 
        if (g->edges == NULL) {
            fprintf(stderr, "newGraph: out of memory
");
            exit(1);
        }
        int v; 
        for (v = 0; v < numVertices; v++) { 
            g->edges[v] = malloc(numVertices * sizeof(int)); 
            if (g->edges[v] == NULL) {
                fprintf(stderr, "newGraph: out of memory
");
                exit(1);
            }
            int j;
            for (j = 0; j < numVertices; j++) {
                g->edges[v][j] = NOWEIGHT;
            }
        } 
        g->nV = numVertices; 
        g->nE = 0; 
    }
    return g;
}

void freeGraph(Graph g) { 
    if (g != NULL) {
        int i; 
        for (i = 0; i < g->nV; i++) { 
            free(g->edges[i]);           // free the mallocs for each row ...
        } 
        free(g->edges);                  // now the malloc for the edges array ...
        free(g);                         // now the malloc for the graph rep
    }
    return;
}

static int validV(Graph g, Vertex v) { // checks if v is in graph 
    return (v >= 0 && v < g->nV); 
}

Edge newEdge(Vertex v, Vertex w, Weight x) { // create an edge from v to w
    Edge e = {v, w, x};
    return e; 
} 

void showEdge(Edge e) { // print an edge and its weight
    printf("%d-%d: %.2f", e.v, e.w, e.x);
    return; 
} 

int isEdge(Edge e, Graph g) { // 0 if not found, else 1; also fill in wgt
   int found = 0;
   if (g != NULL) {
      if (g->edges[e.v][e.w] != NOWEIGHT) {
         found = 1;
      }
   }
   return found;
}

Edge getEdge(Vertex v, Vertex w, Graph g) {
   Edge e = {0, 0, 0.0};
   if (validV(g, v) || validV(g, w)) {
      e.v = v;
      e.w = w;
      e.x = g->edges[v][w];
   }
   return e;
}

int cmpEdge(Edge e1, Edge e2) { // comparison based on edge weight
   int retval = 0;
   if (e1.x < e2.x) {
      retval = -1;
   }
   else if (e1.x > e2.x) {
      retval = 1;
   }
   return retval;
}

void insertEdge(Edge e, Graph g) { // insert an edge into a graph 
   if (g == NULL) {
      fprintf(stderr, "insertEdge: graph not initialised
");
   }
   else {
       if (!validV(g, e.v) || !validV(g, e.w)) {
          fprintf(stderr, "insertEdge: invalid vertices %d-%d
", e.v, e.w);
       }
       else {
          if (!isEdge(e, g)) { // increment nE only if it is new
             g->nE++; 
          }
          g->edges[e.v][e.w] = e.x;
          g->edges[e.w][e.v] = e.x; 
       }
   }
   return;
} 

void removeEdge(Edge e, Graph g) { // remove an edge from a graph 
    if (g == NULL) {
        fprintf(stderr, "removeEdge: graph not initialised
");
    }
    else {
        if (!validV(g, e.v) || !validV(g, e.w)) {
            fprintf(stderr, "removeEdge: invalid vertices
");
        }
        else {
            if (isEdge(e, g) == NOWEIGHT) {   // is edge there?
                g->edges[e.v][e.w] = NOWEIGHT; 
                g->edges[e.w][e.v] = NOWEIGHT; 
                g->nE--; 
            }
        }
    }
    return;
} 

Weight getWeight(Graph g, Vertex v1, Vertex v2) { // get Weight: NOWEIGHT if not existing
    Edge e = {v1, v2}; // not required, but for consistency
    Weight retval = 0.0;

    if (g == NULL) {
        fprintf(stderr, "getWeight: graph not initialised
");
    }
    else {
        if (!validV(g, e.v) || !validV(g, e.w)) {
            fprintf(stderr, "getWeight: invalid vertices
");
        }
        else {
            retval = g->edges[e.v][e.w];
        }
    }
    return retval;
}

void showGraph(Graph g) { // print a graph
    if (g == NULL) {
        printf("NULL graph
");
    }
    else {
        printf("V=%d, E=%d
", g->nV, g->nE); 
        int i;
        for (i = 0; i < g->nV; i++) { 
            int nshown = 0; 
            int j;
            for (j = 0; j < g->nV; j++) { 
                if (g->edges[i][j] != NOWEIGHT) { 
                    printf("%d %d:%.2f ", i, j, g->edges[i][j]);
                    nshown++;
                }
            }
            if (nshown > 0) {
                printf("
");
            }
        }
    }
    return;
}

 WeGraph.h  

// WeGraph.h: an interface for a weighted graph ADT
#include <math.h>

typedef float Weight;             // define a WEIGHT
#define NOWEIGHT  -1.0
#define MAXWEIGHT INFINITY

typedef int Vertex;               // define a VERTEX
#define UNVISITED -1
#define VISITED 1

typedef struct { 
  Vertex v; 
  Vertex w; 
  Weight x;
} Edge;

typedef struct graphRep *Graph;   // define a GRAPH

Graph newGraph(int);
void  freeGraph(Graph);
void  showGraph(Graph);

void insertEdge(Edge, Graph);
void removeEdge(Edge, Graph);
void showEdge(Edge);
int  isEdge(Edge, Graph);
Edge newEdge(Vertex, Vertex, Weight);
Edge getEdge(Vertex, Vertex, Graph);
int  cmpEdge(Edge, Edge);

Weight getWeight(Graph, Vertex, Vertex);
原文地址:https://www.cnblogs.com/alex-bn-lee/p/11289220.html