💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[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; } ```