[TOC]
# 算法思想
![](https://box.kancloud.cn/2016-04-18_5714a4c764c77.gif)
Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。
其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。
初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时对数组dist作必要的修改。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。
例如:
![](https://box.kancloud.cn/2016-04-18_5714a66d98043.jpg)
应用dijkstra算法得到的如下表:
![](https://box.kancloud.cn/2016-04-18_5714a6786f06b.jpg)
# 分析
### 贪心选择性质
### 最优子结构
# 代码实现-1
```
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct {
int vertex;
int weight;
} edge_t;
typedef struct {
edge_t **edges;
int edges_len;
int edges_size;
int dist;
int prev;
int visited;
} vertex_t;
typedef struct {
vertex_t **vertices;
int vertices_len;
int vertices_size;
} graph_t;
typedef struct {
int *data;
int *prio;
int *index;
int len;
int size;
} heap_t;
void add_vertex (graph_t *g, int i) {
if (g->vertices_size < i + 1) {
int size = g->vertices_size * 2 > i ? g->vertices_size * 2 : i + 4;
g->vertices = realloc(g->vertices, size * sizeof (vertex_t *));
for (int j = g->vertices_size; j < size; j++)
g->vertices[j] = NULL;
g->vertices_size = size;
}
if (!g->vertices[i]) {
g->vertices[i] = calloc(1, sizeof (vertex_t));
g->vertices_len++;
}
}
void add_edge (graph_t *g, int a, int b, int w) {
a = a - 'a';
b = b - 'a';
add_vertex(g, a);
add_vertex(g, b);
vertex_t *v = g->vertices[a];
if (v->edges_len >= v->edges_size) {
v->edges_size = v->edges_size ? v->edges_size * 2 : 4;
v->edges = realloc(v->edges, v->edges_size * sizeof (edge_t *));
}
edge_t *e = calloc(1, sizeof (edge_t));
e->vertex = b;
e->weight = w;
v->edges[v->edges_len++] = e;
}
heap_t *create_heap (int n) {
heap_t *h = calloc(1, sizeof (heap_t));
h->data = calloc(n + 1, sizeof (int));
h->prio = calloc(n + 1, sizeof (int));
h->index = calloc(n, sizeof (int));
return h;
}
void push_heap (heap_t *h, int v, int p) {
int i = h->index[v] || ++h->len;
int j = i / 2;
while (i > 1) {
if (h->prio[j] < p)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
j = j / 2;
}
h->data[i] = v;
h->prio[i] = p;
h->index[v] = i;
}
int min (heap_t *h, int i, int j, int k) {
int m = i;
if (j <= h->len && h->prio[j] < h->prio[m])
m = j;
if (k <= h->len && h->prio[k] < h->prio[m])
m = k;
return m;
}
int pop_heap (heap_t *h) {
int v = h->data[1];
h->data[1] = h->data[h->len];
h->prio[1] = h->prio[h->len];
h->index[h->data[1]] = 1;
h->len--;
int i = 1;
while (1) {
int j = min(h, i, 2 * i, 2 * i + 1);
if (j == i)
break;
h->data[i] = h->data[j];
h->prio[i] = h->prio[j];
h->index[h->data[i]] = i;
i = j;
}
h->data[i] = h->data[h->len + 1];
h->prio[i] = h->prio[h->len + 1];
h->index[h->data[i]] = i;
return v;
}
void dijkstra (graph_t *g, int a, int b) {
int i, j;
a = a - 'a';
b = b - 'a';
for (i = 0; i < g->vertices_len; i++) {
vertex_t *v = g->vertices[i];
v->dist = INT_MAX;
v->prev = 0;
v->visited = 0;
}
vertex_t *v = g->vertices[a];
v->dist = 0;
heap_t *h = create_heap(g->vertices_len);
push_heap(h, a, v->dist);
while (h->len) {
i = pop_heap(h);
if (i == b)
break;
v = g->vertices[i];
v->visited = 1;
for (j = 0; j < v->edges_len; j++) {
edge_t *e = v->edges[j];
vertex_t *u = g->vertices[e->vertex];
if (!u->visited && v->dist + e->weight <= u->dist) {
u->prev = i;
u->dist = v->dist + e->weight;
push_heap(h, e->vertex, u->dist);
}
}
}
}
void print_path (graph_t *g, int i) {
int n, j;
vertex_t *v, *u;
i = i - 'a';
v = g->vertices[i];
if (v->dist == INT_MAX) {
printf("no path\n");
return;
}
for (n = 1, u = v; u->dist; u = g->vertices[u->prev], n++)
;
char *path = malloc(n);
path[n - 1] = 'a' + i;
for (j = 0, u = v; u->dist; u = g->vertices[u->prev], j++)
path[n - j - 2] = 'a' + u->prev;
printf("%d %.*s\n", v->dist, n, path);
}
int main () {
graph_t *g = calloc(1, sizeof (graph_t));
add_edge(g, 'a', 'b', 7);
add_edge(g, 'a', 'c', 9);
add_edge(g, 'a', 'f', 14);
add_edge(g, 'b', 'c', 10);
add_edge(g, 'b', 'd', 15);
add_edge(g, 'c', 'd', 11);
add_edge(g, 'c', 'f', 2);
add_edge(g, 'd', 'e', 6);
add_edge(g, 'e', 'f', 9);
dijkstra(g, 'a', 'e');
print_path(g, 'e');
return 0;
}
```