Heap+Dijkstra堆优化的Dijkstra
来源:互联网 发布:jenkins的数据库 编辑:程序博客网 时间:2024/05/29 09:38
前面说到“原生的Dijkstra”,由于Dijkstra采用的是贪心策略,在贪心寻找当前距离源结点最短的结点时需要遍历所有的结点,这必然会导致效率的下降,时间复杂度为n^n。因此当数据量较大时会消耗较长时间。为了提高Dijkstra的效率,只有对Dijkstra的贪心策略进行改进。
由于Dijkstra采用的贪心策略是每次寻找最短距离的结点并将其放入存放所有已知最短距离结点的S集合中,可以联想到堆以及优先级队列这些数据结构,这些结构都能非常高效地提供当前状态距离最短的结点。实践也可以证明这两种优化对于Dijkstra的效率提升是非常明显的。
另外需要提到的是优先队列优化的Dijkstra和堆优化的Dijkstra效率相差不多,但是优先队列优化的方式却非常好实现,因为java类库中有PriorityQueue对象,该对象就是优先队列。但是对于堆优化来说就比较复杂了,因为需要自己动手实现最小堆,这样既复杂又容易出错,因此如果是想对Dijksra进行优化的话,首推PriorityQueue+Dijkstra即优先队列优化的Dijkstra。
下面还是以蓝桥杯的那道”最短路“题目为例展示Heap+Dijkstra堆优化的Dijkstra
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
1 2 -1
2 3 -1
3 1 2
-2
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
下面是堆优化的Dijkstra代码:
import java.util.HashMap;import java.util.Iterator;import java.util.Scanner;import java.util.Set;/** * Heap + Dijkstra算法求单源最短路径 * 采用邻接表存储图数据 * 邻接表结构: * 头结点--Node对象数组 * 邻接节点--Node对象中的HashMap * * @author DuXiangYu * */public class DijKstra_link_Heap {static int nodeCount;static int edgeCount;// 邻接表表头数组static Node[] firstArray;// 最短路径数组static int[][] dist;static int[] ref;static int max = 1000000;/** * 结点类 * * @author DuXiangYu */static class Node {// 邻接顶点mapprivate HashMap<Integer, Integer> map = null;public void addEdge(int end, int edge) {if (this.map == null) {this.map = new HashMap<Integer, Integer>();}this.map.put(end, edge);}}public static void main(String[] args) {Scanner sc = new Scanner(System.in);nodeCount = sc.nextInt();edgeCount = sc.nextInt();firstArray = new Node[nodeCount + 1];for (int i = 0; i < nodeCount + 1; i++) {firstArray[i] = new Node();}for (int i = 0; i < edgeCount; i++) {int begin = sc.nextInt();int end = sc.nextInt();int edge = sc.nextInt();firstArray[begin].addEdge(end, edge);}sc.close();long begin = System.currentTimeMillis();djst();long end = System.currentTimeMillis();System.out.println(end - begin + "ms");}/** * Heap + Dijkstra算法实现 */private static void djst() {dist = new int[2][nodeCount + 1];ref = new int[nodeCount + 1];Node tempNode = firstArray[1];for (int i = 2; i < nodeCount + 1; i++) {HashMap<Integer, Integer> tempMap = tempNode.map;dist[0][i] = tempMap.containsKey(i) ? tempMap.get(i) : max;dist[1][i] = i;ref[i] = i;minUp(i);}int flag = nodeCount;while (flag >= 2) {int index = dist[1][2];changeKey(2, flag);maxDown(2, --flag);// 用indx这个点去更新它的邻接点到开始点的距离HashMap<Integer, Integer> m = firstArray[index].map;if (m == null) {continue;}Set<Integer> set = m.keySet();Iterator<Integer> it = set.iterator();while (it.hasNext()) {int num = it.next();if (m.get(num) + dist[0][flag + 1] < dist[0][ref[num]]) {dist[0][ref[num]] = m.get(num) + dist[0][flag + 1];minUp(ref[num]);}}}for (int i = 2; i < nodeCount + 1; i++) {System.out.println(dist[0][ref[i]]);}}/** * 最大值下沉 * * @param index * @param end */private static void maxDown(int index, int end) {int temp = dist[0][index];int left = index * 2 - 1;while (left <= end) {// 判断左右子节点大小if (left + 1 <= end && dist[0][left + 1] < dist[0][left]) {left++;}// 如果左右子节点都比temp大的话结束下沉操作if (dist[0][left] > temp) {break;}// 交换子节点和父节点changeKey(index, left);index = left;left = index * 2 - 1;}}/** * 小值上升 * * @param n */private static void minUp(int n) {int f = (n + 1) / 2;while (f >= 2 && dist[0][f] > dist[0][n]) {changeKey(f, n);n = f;f = (n + 1) / 2;}}/** * 交换两个值 * * @param a * @param b */private static void changeKey(int a, int b) {int n = dist[1][a];int m = dist[1][b];int temp = ref[n];ref[n] = ref[m];ref[m] = temp;temp = dist[0][a];dist[0][a] = dist[0][b];dist[0][b] = temp;temp = dist[1][a];dist[1][a] = dist[1][b];dist[1][b] = temp;}}
对于“原生的Dijkstra”中的那个较大测试数据:10000个结点和100000条边来说,该优化的Dijkstra执行实现平均为250ms,而无优化的Dijkstra对于该数据的平均执行实现为2200ms,性能提升了88%,可以看得出来对于性能的提升是非常明显的:
- Heap+Dijkstra堆优化的Dijkstra
- 堆优化的Dijkstra
- 最短路算法 堆优化 dijkstra+heap
- 堆优化的Dijkstra算法
- 堆优化的dijkstra(迪杰斯特拉)
- Dijkstra + Heap优化模板
- dijkstra + heap 优化
- 白书上的dijkstra+堆优化/dijkstra的一些性质
- DIJKSTRA堆优化
- Dijkstra + 堆优化
- 堆优化Dijkstra模版
- Dijkstra+堆优化
- 堆优化Dijkstra
- 堆优化Dijkstra
- Dijkstra + 堆优化
- Dijkstra+堆优化 模板
- Dijkstra堆优化
- [ 模板 ] 堆优化Dijkstra
- Java中Runnable和Thread以及Callable的区别
- win7系统 64为 corel 中默认字体如何设置?
- 使用postman和editthiscookies
- 一个典型的生产者和消费者的题目和实现
- IOS Assigning to 'id<UITabBarControllerDelegate>' from incompatible type...
- Heap+Dijkstra堆优化的Dijkstra
- 如何以root用户远程访问MySQL
- 开始leetcode day9:Candy
- JSON之JSONArray的使用
- Oracle字符集修改
- 引用类型(4)Function类型
- 开源 java CMS - FreeCMS2.3 积分记录
- 图像的乘法操作immultiply.m
- 二分图