图论算法之最短路径(Dijkstra算法)
来源:互联网 发布:powell算法 编辑:程序博客网 时间:2024/05/08 21:43
1 算法介绍
如果图是有向赋权图,那么问题将比无权图困难。
Dijkstra算法向无权图最短路径算法一样。按阶段进行。在每一个阶段,Dijkstra算法选择一个顶点v。它在所有未知顶点中具有最小距离的dist,同时算法声明从s到v的最短路径是已知的。阶段的其余更新邻接点的信息。
表1表示初始配置。假设开始s是v0。第一个选择的顶点是v0.路径长0.该顶点标记为已知。既然v0已知,那么某些表项就需要调整。邻接到v0的顶点是v1到v3.这两个顶点的项得到调整。如表2。
下一步,选取v4并标记为已知。顶点v2,v4,v5,v6是邻接的顶点,而实际上都需要调整。如表3。
接着选择v1。v3是邻接的点,但已经是已知的,因此对它没有工作要做。v4是邻接点但不做调整,因为经过v1的值为2 + 10 = 12,而长为3的路径已经是已知的。如表4。
下一个被选取的顶点是v4,其值为3。v6是唯一的邻接顶点。但是它不用调整。因为 3 + 6 > 5。然后选取v2,对v5的距离下调到3 + 5 = 8。如表5。
再下一个选取的顶点是v6。v5下调到5 + 1 = 6。如表6。
最后,我们选择v5。如表7。
下图是最后的结果。
2 算法实现
dijkstra函数是核心算法,initGraph和initArr负责初始化图G。算法用到二叉堆以及链表,我把它们放在下面附录中。
//// LinkList.c// Unweighted//// Created by Wuyixin on 2017/6/6.// Copyright © 2017年 Coding365. All rights reserved.//#include "LinkList.h"int UNAVAILABLE = INT_MIN;/* 链表初始化 */LinkedList initList(){ LinkedList h = malloc(sizeof(struct Node)); if (h == NULL) exit(EXIT_FAILURE); h->next = NULL; h->data = UNAVAILABLE; return h;}/* 插入元素 */ElemType insert_l(ElemType x,LinkedList list){ PtoNode current; current = list; while (current->next != NULL) current = current->next; /* 生成新节点 */ PtoNode n = (PtoNode)malloc(sizeof(struct Node)); if (n == NULL) exit(EXIT_FAILURE); n->data = x; n->next = NULL; current->next = n; return x;}/* 删除链表 */void deleteList(LinkedList list){ if (list == NULL) return; PtoNode node,old; node = list; while (node->next != NULL){ old = node; node = node->next; free(old); }}/* 打印链表 */void printList(LinkedList list){ PtoNode node; node = list->next; while (node!= NULL ) { printf("%d ",node->data); node = node->next; } printf("\n");}
3 附录:二叉堆与链表
3.1 Node结构
//// Node.h// Dijkstra2//// Created by Wuyixin on 2017/6/11.// Copyright © 2017年 Coding365. All rights reserved.//#ifndef Node_h#define Node_h#include <stdio.h>typedef int ElemType;struct Node{ ElemType data; struct Node* next; int dist; int known; int path; int cost;};#endif /* Node_h */
3.2 二叉堆
(1)头文件
//// BinHeap.h// PriorityQueue//// Created by Wuyixin on 2017/5/29.// Copyright © 2017年 Coding365. All rights reserved.//#ifndef BinHeap_h#define BinHeap_h#include <stdio.h>#include <stdlib.h>#include <limits.h>#include "Node.h"#define PRIORITY_QUEUE_SIZE_MIN 50struct HeapStruct;typedef struct HeapStruct *PriorityQueue;/* 元素类型 */typedef struct Node * ElementType;/* 差值 */typedef int DIFFERENCE;extern const int DATA_MIN;//最小值,用来标记空节点/* 自定义非法值 */void defineInvalidValue(ElementType invalid);/* 初始化 */PriorityQueue init_queue(int max_elements);/* 构建堆操作,把n个关键字(任意顺序)作为输入并把它们放入到空堆中*/PriorityQueue build_heap(PriorityQueue h ,ElementType arr,unsigned int n,int (*compare)(void*,void*));/* 销毁堆 */void destroy(PriorityQueue h);/* 置空堆 */void make_empty(PriorityQueue h);/* 插入 */void insert_h(ElementType x,PriorityQueue h,int (*compare)(void*,void*));/* 删除最小 */ElementType delete_min(PriorityQueue h,int (*compare)(void*,void*));/* 删除元素 */ElementType delete_element(int p ,PriorityQueue h,DIFFERENCE infinity,ElementType (*change)(ElementType,DIFFERENCE),int (*compare)(void*,void*));/* 查找最小 */ElementType find_min(PriorityQueue h);/* 降低关键字的值 */ElementType decrease_key(int p,DIFFERENCE d,ElementType (*change)(ElementType,DIFFERENCE),PriorityQueue h,int (*compare)(void*,void*));/* 增加关键字的值 */ElementType increase_key(int p,DIFFERENCE d,ElementType (*change)(ElementType,DIFFERENCE),PriorityQueue h,int (*compare)(void*,void*));/* 是否空 */int is_empty(PriorityQueue h);/* 是否满 */int is_full(PriorityQueue h);/* 遍历堆 */void travel_queue(PriorityQueue h,void handle(ElementType));struct HeapStruct{ int capacity; int size; ElementType *elements;};#endif /* BinHeap_h */
(2)实现文件
//// BinHeap.c// PriorityQueue//// Created by Wuyixin on 2017/5/29.// Copyright © 2017年 Coding365. All rights reserved.//#include "BinHeap.h"const int DATA_MIN = INT_MIN;static ElementType binHeapInvalidValue;static int percolate_up(int p,ElementType value,PriorityQueue h,int (*compare)(void*,void*));static int percolate_down(int p,ElementType value,PriorityQueue h,int (*compare)(void*,void*));static void error(char* message){ printf("%s\n",message);}static void fatal_error(char* message){ error(message); exit(EXIT_FAILURE);}/* 上滤 *//* 一个元素的值降低,或者在堆的末尾增加新值,都会用到此操作。此操作的特点是让节点“往上升” *//* return 返回上滤后的新位置*/static int percolate_up(int p,ElementType value,PriorityQueue h,int (*compare)(void*,void*)){ if (is_empty(h)) return DATA_MIN; if (p < 1 || p > h->size) return DATA_MIN; /* 由于h->elements[0]的值是DATA_MIN,所以可以作为循环终止的条件 */ int i; for (i = p; h->elements[i/2] != NULL && compare(value,h->elements[i/2]) < 0; i /= 2) { h->elements[i] = h->elements[i/2]; } return i;}/* 下滤 *//* 一个元素的值增加,或者删除堆的最小元(根),都会用到此操作。此操作的特点是让节点“往下降” */static int percolate_down(int p,ElementType value,PriorityQueue h,int (*compare)(void*,void*)){ if (is_empty(h)) return DATA_MIN; if (p < 1 || p > h->size) return DATA_MIN; int i; int child; for (i = p; 2 * i <= h->size; i = child) { child = 2 * i; /* 比较左右孩子,取出小的元素上滤*/ /* 直到"空穴"来到最后一层(树叶)或者 “空穴”的两个孩子都比last_elem的值要大,找到这个位置*/ if (child != h->size && compare( h->elements[child + 1],h->elements[child]) < 0) child++; if (compare(value,h->elements[child]) > 0){ h->elements[i] = h->elements[child]; } else break; } return i; }void defineInvalidValue(ElementType invalid){ binHeapInvalidValue = invalid;}PriorityQueue init_queue(int max_elements){ /* 给堆分配的长度太小 */ if (max_elements < PRIORITY_QUEUE_SIZE_MIN) error("Priority queue size is too small"); PriorityQueue h = malloc(sizeof(struct HeapStruct)); if (h == NULL) fatal_error("Out of space!!!"); /* 数组第一个元素不存储节点,根从第二个元素开始,因为这样节点的父亲、左孩子、右孩子的表达式比较清楚。因此实际分配的大小要比max_elements大1 */ h->elements = malloc((max_elements + 1) * sizeof(ElementType)); if (h->elements == NULL) fatal_error("Out of space!!!"); h->size = 0; h->capacity = max_elements; h->elements[0] = binHeapInvalidValue;/* 做标记用 */ return h;}PriorityQueue build_heap(PriorityQueue h ,ElementType arr,unsigned int n,int (*compare)(void*,void*)){ if (h == NULL) return h; if (n == 0) return h; int i = 0; /* 将数组中的元素的值复制到堆中(无序) */ ElementType* p = h->elements + 1; while (i < n){ *p++ = (arr + i++),h->size++; } i = n / 2; while(i > 0) percolate_down(i, h->elements[i], h,compare),i--; return h;}void destroy(PriorityQueue h){ free(h->elements); free(h);}void make_empty(PriorityQueue h){ /* 其实就是把size变成零,虽然堆里的每个节点的值还在,但都是无效的。 */ h->size = 0;}void insert_h(ElementType x,PriorityQueue h,int (*compare)(void*,void*)){ int i; if (is_full(h)) error("Priority queue is full"); /* 插入元素先放在堆的末尾,然后经过上滤的过程找到合适的位置并插入 */ /* 注意++h->size已经把size加1 */ i = percolate_up(++h->size, x, h,compare); h->elements[i] = x; }ElementType delete_min(PriorityQueue h,int (*compare)(void*,void*)){ if (is_empty(h)) return binHeapInvalidValue; /* 注意h->size--已经把size减1 */ ElementType last_elem = h->elements[h->size--]; ElementType min_elem = h->elements[1]; /* 把最小元删除,经过下滤过程,把堆序重新调整*/ int i = percolate_down(1, last_elem, h,compare); if (i != DATA_MIN) h->elements[i] = last_elem; return min_elem;}/* 删除位置p的节点。这通过首先执行decrease_key(p,∞,h),然后在执行delete_min(h)来完成*/ElementType delete_element(int p ,PriorityQueue h,DIFFERENCE infinity,ElementType (*change)(ElementType,DIFFERENCE),int (*compare)(void*,void*)){ if (is_empty(h)) return binHeapInvalidValue; if (p < 1 || p > h->size) return h->elements[0]; ElementType elem = h->elements[p]; decrease_key(p, infinity,change, h,compare); delete_min(h,compare); return elem;}ElementType find_min(PriorityQueue h){ if (is_empty(h)) return h->elements[0]; return h->elements[1];}/* 该操作降低位置p处的关键值,降值的幅度为正的量d。由于这可能破坏堆的序,因此必须通过上滤对堆进行调整 */ElementType decrease_key(int p,DIFFERENCE d,ElementType (*change)(ElementType,DIFFERENCE),PriorityQueue h,int (*compare)(void*,void*)){ if (is_empty(h)) return binHeapInvalidValue; if (p < 1 || p > h->size) return h->elements[0]; if (d <= 0) return h->elements[0]; ElementType value = change(h->elements[p],-d); int i = percolate_up(p, value, h,compare); h->elements[i] = value; return value;}/* 该操作增加位置p处的关键值,增值的幅度为正的量d。由于这可能破坏堆的序,因此必须通过下滤对堆进行调整 */ElementType increase_key(int p,DIFFERENCE d,ElementType (*change)(ElementType,DIFFERENCE),PriorityQueue h,int (*compare)(void*,void*)){ if (is_empty(h)) return binHeapInvalidValue; if (p < 1 || p > h->size) return h->elements[0]; if (d <= 0) return h->elements[0]; ElementType value = change(h->elements[p] , d) ; int i = percolate_down(p, value, h,compare); h->elements[i] = value; return value;}int is_empty(PriorityQueue h){ return h->size == 0;}int is_full(PriorityQueue h){ return h->size >= h->capacity;}void travel_queue(PriorityQueue h,void handle(ElementType)){ if (!is_empty(h)){ int i = 0; while (i++ < h->size) handle(h->elements[i]); }}
3.3 链表
(1)头文件
//// LinkList.h// Unweighted//// Created by Wuyixin on 2017/6/6.// Copyright © 2017年 Coding365. All rights reserved.//#ifndef LinkList_h#define LinkList_h#include <stdio.h>#include <limits.h>#include <stdlib.h>#include "Node.h"typedef struct Node *LinkedList,*PtoNode;extern int UNAVAILABLE;/* 链表初始化 */LinkedList initList();/* 插入元素 */ElemType insert_l(ElemType x,LinkedList list);/* 删除链表 */void deleteList(LinkedList list);/* 打印链表 */void printList(LinkedList list);#endif /* LinkList_h */
(2)实现文件
//// LinkList.c// Unweighted//// Created by Wuyixin on 2017/6/6.// Copyright © 2017年 Coding365. All rights reserved.//#include "LinkList.h"int UNAVAILABLE = INT_MIN;/* 链表初始化 */LinkedList initList(){ LinkedList h = malloc(sizeof(struct Node)); if (h == NULL) exit(EXIT_FAILURE); h->next = NULL; h->data = UNAVAILABLE; return h;}/* 插入元素 */ElemType insert_l(ElemType x,LinkedList list){ PtoNode current; current = list; while (current->next != NULL) current = current->next; /* 生成新节点 */ PtoNode n = (PtoNode)malloc(sizeof(struct Node)); if (n == NULL) exit(EXIT_FAILURE); n->data = x; n->next = NULL; current->next = n; return x;}/* 删除链表 */void deleteList(LinkedList list){ if (list == NULL) return; PtoNode node,old; node = list; while (node->next != NULL){ old = node; node = node->next; free(old); }}/* 打印链表 */void printList(LinkedList list){ PtoNode node; node = list->next; while (node!= NULL ) { printf("%d ",node->data); node = node->next; } printf("\n");}
阅读全文
0 0
- 图论算法之最短路径(Dijkstra算法)
- 图论之最短路径-------Dijkstra算法
- 图之最短路径:迪杰斯特拉(Dijkstra)算法
- 最短路径算法之Dijkstra算法(邻接矩阵实现)
- 图算法 最短路径 Dijkstra算法
- 最短路径问题Dijkstra(图论算法)
- 最短路径之Dijkstra算法
- 最短路径之Dijkstra+Floyd算法
- 三、最短路径之Dijkstra算法
- 最短路径 之 Dijkstra算法
- 最短路径之Dijkstra算法
- 最短路径之Dijkstra算法
- 最短路径之Dijkstra算法
- 最短路径之Dijkstra算法
- 最短路径之Dijkstra+Floyd算法
- 最短路径之Dijkstra算法
- Node:最短路径算法之Dijkstra
- 最短路径之迪杰斯特拉(Dijkstra)算法
- [leetCode刷题笔记]599. Minimum Index Sum of Two Lists
- Linux安装Apache
- 图论算法之最短路径(具有负边值的图)
- Android_常用控件
- C语言.动态链表.随笔
- 图论算法之最短路径(Dijkstra算法)
- 图论算法之最短路径(有向无权图)
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践11——如何买玫瑰
- 操作系统实验报告 lab6
- 《C语言及程序设计初步》_1.11算术运算符与算术表达式_实践12——玩数字
- 模式识别——正态训练样本分类估计
- 使用zipkin做分布式链路监控
- 机器学习-梯度下降法
- Oracle存储过程及调用