您的位置:首页 > 编程语言 > Java开发

Dijkstra 算法用优先队列的java实现

2017-04-08 01:44 423 查看
dijkstra这个算法的意思百度下大概就能明白。我主要讲的是如何实现。

首先,我们如何用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());
}
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: