Dijkstra 算法用优先队列的java实现
2017-04-08 01:44
423 查看
dijkstra这个算法的意思百度下大概就能明白。我主要讲的是如何实现。
首先,我们如何用java去保存一张有向图?
我用hashmap去存它的起点位置,然后value用list加节点的方式,感觉就像链表一样。去存储
地图模板
然后为了凸显出链表的效率。我们先来个普通模式的dijkstra算法的实现,这个方式去实现其算法复杂度是O(V^2)V是节点数量
大致就是这样实现下。
然后我们就要讨论为什么要用有限队列?因为它是堆的形式。堆便于取出最值,如果一个算法中需要多次取最大或者最小值,那么堆就是个最好的存放容器,其建堆只要O(N)的时间,增删,堆化时间复杂度也只要O(logn)。有很大的优势。
用堆去存储 复杂度降低到O(VlogV)
代码如下
首先,我们如何用java去保存一张有向图?
我用hashmap去存它的起点位置,然后value用list加节点的方式,感觉就像链表一样。去存储
地图模板
//创建地图 /* * S——16——>C—— 2——>D * | \ ^ ^ ^ * 4 8 | \ | * | \ 7 5 6 * v v | \ | * A—— 3——>B—— 1——>E */ class Graph { Map<Character,List<Node>> map=new HashMap<Character,List<Node>>();//输出的地图 Graph() { List<Node> list=new ArrayList<Node>(); list.add(new Node('S','A',4)); list.add(new Node('S','B',8)); list.add(new Node('S','C',16)); list.add(new Node('A','B',3)); list.add(new Node('B','C',7)); list.add(new Node('B','E',1)); list.add(new Node('C','D',2)); list.add(new Node('E','C',5)); list.add(new Node('E','D',6)); for(int i=0;i<list.size();i++) { List<Node> temp=map.get(list.get(i).getSrc()); if(temp==null) temp=new ArrayList<Node>(); temp.add(list.get(i)); map.put(list.get(i).getSrc(), temp); } } } class Node { private Character src;//起点 private Character des;//终点 private int len; //距离长度 private int path=Integer.MAX_VALUE;//初始设置为无穷长 boolean die=false; //访问过一次后就死亡 Node(){} Node(Character src,Character des,int len) { this.src=src; this.des=des; this.len=len; } void setPath(int path) { this.path=path; } int getPath() { return path; } Char d32c acter getSrc() { return src; } Character getDes() { return des; } int getLen() { return len; } }
然后为了凸显出链表的效率。我们先来个普通模式的dijkstra算法的实现,这个方式去实现其算法复杂度是O(V^2)V是节点数量
public class Dijkstra { public static Map<Character,Integer> dijkstra(Map<Character,List<Node>> map,Character c) { Queue<Node> heap=new LinkedList<Node>(); //初始节点 Node root=new Node(c,c,0); root.setPath(0); heap.add(root); Map<Character,Integer> result=new HashMap<Character,Integer>(); while(!heap.isEmpty()) { Node x=heap.poll(),y = null; List<Node> temp=map.get(x.getDes()); if(temp==null) continue; for(int i=0;i<temp.size();i++) { y=temp.get(i); if(y.getPath()>x.getPath()+y.getLen()) { temp.get(i).setPath(x.getPath()+y.getLen()); if(temp.get(i).die==false) { heap.add(temp.get(i)); temp.get(i).die=true; } if(result.get(temp.get(i).getDes())==null) { result.put(temp.get(i).getDes(),temp.get(i).getPath()); } if(result.get(temp.get(i).getDes())>temp.get(i).getPath()) { result.put(temp.get(i).getDes(),temp.get(i).getPath()); } } } } return result; } public static void main(String[] argc) { Graph graph=new Graph(); Map<Character,Integer> result=dijkstra(graph.map,'S'); for(Map.Entry<Character,Integer> entry:result.entrySet()) { System.out.println("S-->"+entry.getKey()+" 长度"+entry.getValue()); } } }
大致就是这样实现下。
然后我们就要讨论为什么要用有限队列?因为它是堆的形式。堆便于取出最值,如果一个算法中需要多次取最大或者最小值,那么堆就是个最好的存放容器,其建堆只要O(N)的时间,增删,堆化时间复杂度也只要O(logn)。有很大的优势。
用堆去存储 复杂度降低到O(VlogV)
代码如下
import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.PriorityQueue; //创建地图 /* * S——16——>C—— 2——>D * | \ ^ ^ ^ * 4 8 | \ | * | \ 7 5 6 * v v | \ | * A—— 3——>B—— 1——>E */ class Graph { Map<Character,List<Node>> map=new HashMap<Character,List<Node>>();//输出的地图 Graph() { List<Node> list=new ArrayList<Node>(); list.add(new Node('S','A',4)); list.add(new Node('S','B',8)); list.add(new Node('S','C',16)); list.add(new Node('A','B',3)); list.add(new Node('B','C',7)); list.add(new Node('B','E',1)); list.add(new Node('C','D',2)); list.add(new Node('E','C',5)); list.add(new Node('E','D',6)); for(int i=0;i<list.size();i++) { List<Node> temp=map.get(list.get(i).getSrc()); if(temp==null) temp=new ArrayList<Node>(); temp.add(list.get(i)); map.put(list.get(i).getSrc(), temp); } } } class Node { private Character src;//起点 private Character des;//终点 private int len; //距离长度 Node(){} Node(Character src,Character des,int len) { this.src=src; this.des=des; this.len=len; } Character getSrc() { return src; } Character getDes() { return des; } int getLen() { return len; } } public class Dijkstra2 { static Map<Character, Integer> dijkstra(Map<Character,List<Node>> graph,Character source) { //堆的初始化 PriorityQueue<Map.Entry<Character, Integer>> queue=new PriorityQueue<Map.Entry<Character, Integer>>((a,b)->a.getValue()-b.getValue()); Map<Character, Integer> map=new HashMap<Character, Integer>(); map.put(source, 0); queue.add(map.entrySet().iterator().next()); Map<Character, Integer> visited=new HashMap<Character, Integer>(); while(!queue.isEmpty()) { //从堆中获取最小距离的节点 Entry<Character, Integer> temp=queue.poll(); //讲距离值添加到visited if(visited.get(temp.getKey())==null) visited.put(temp.getKey(), temp.getValue()); if(graph.get(temp.getKey())==null) { continue; } //更新与temp相邻各节点neighbour的distance for(int i=0; i<graph.get(temp.getKey()).size();i++) { if(visited.get(graph.get(temp.getKey()).get(i).getDes())!=null) { continue; } Map<Character, Integer> temp2=new HashMap<Character, Integer>(); temp2.put(graph.get(temp.getKey()).get(i).getDes(), temp.getValue()+graph.get(temp.getKey()).get(i).getLen()); queue.add(temp2.entrySet().iterator().next()); } } return visited; } public static void main(String[] argc) { Graph graph=new Graph(); Map<Character, Integer> result=dijkstra(graph.map,'S'); for(Map.Entry<Character,Integer> entry:result.entrySet()) { System.out.println("S-->"+entry.getKey()+" 长度"+entry.getValue()); } } }
相关文章推荐
- 算法(第四版)学习笔记之java实现基于堆的优先队列
- 优先队列的实现 Java数据结构与算法
- Java 实现Dijkstra(迪杰斯特拉)算法
- (数据结构与算法分析 七)------优先队列中的二叉堆的实现( Java语言描述)
- 算法设计之,堆,堆排序,基于最大堆的最大优先队列的实现(C++实现)
- java使用堆结构实现优先队列
- 优先队列 算法导论 java语言
- java_实现先来先服务(FCFS)短作业优先算法(SJF)
- 算法学习 - 优先队列的二叉堆实现
- 算法基础(六):广度优先探索迷宫路径(队列实现!)—超详细版!
- 基于算法导论6.5用最大堆实现的优先队列(C++)
- 算法笔记(堆实现的最大优先队列)
- 数据结构之优先队列--二叉堆(Java实现)
- 图论算法——基于的java实现(dijkstra,bfs,dfs,floyd)
- Dijkstra单源最短路径算法; 优先队列+静态数组邻接表; STL优先队列还是没想明白排序原则;
- 算法入门--最大堆实现优先队列
- uva 11374 最短路+记录路径 好题 dijkstra优先队列优化算法 邻接表法 可做模板 G++提交
- 一个用Dijkstra算法实现的路由算法的java程序——1 GraphAdjList类
- 最短路径算法比较(Dijkstra、Bellman-Ford、SPFA)及实现(Java)