有向图的最短路径Dijkstra算法实现
图学习笔记索引
001自定义输入流In类实现
002背包数据类型Bag实现
003无向图数据类型实现
004基于图的深度优先搜索
005使用深度优先搜索找图中的所有连通分量
005-1基于深度优先搜索查找图中连通路径
006基于深度优先搜索判断图中是否存在环
007基于深度优先搜索判断一个无向图图是否是一个二分图
008广度优先搜索查找连通图中的最短路径
009有向图数据类型实现
010有向图的可达性
011带权重的无向边数据类型Edge实现
012加权无向图数据类型实现
013寻找有向环
014有向图中基于深度优先搜索的顶点排序
015查找、排序、符号表、散列表等算法实现(1)
016最小生成树Prim算法延时实现
017最小生成树Prim算法即时实现
018加权有向边及加权有向图的实现
019有向图的最短路径Dijkstra算法实现
本文参考《算法(第4版)》
1.依赖类
从文件中读取图的顶点关系。
tinyEWD.txt中的内容:
8
15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93
点击文字获取:001自定义输入流In类实现
点击文字获取:索引优先队列IndexMinPQ实现
索引优先队列IndexMinPQ实现
package algorithms.rank;
import java.util.Arrays;
import java.util.Comparator;
public class IndexMinPQ<T> {
private int[] pq;
private int[] qp;
private Object[] element;
private final int capacity;
private int size;
private Comparator<? super T> cmp;
private static class Cmp<T> implements Comparator<T>{
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public int compare(T t1, T t2) {
return ((Comparable)(t1)).compareTo(t2);
}
}
private static void swap(int[] a, int i, int j){
int tmp;
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
//与对象关联的整数范围是[0,capacity-1]
public IndexMinPQ(int capacity, Comparator<T> cmp){
this.capacity = capacity;
pq = new int[capacity+1];
qp = new int[capacity+1];
Arrays.fill(qp, -1); //初始化qp中的每个元素为-1;
element = new Object[capacity+1];
if(cmp == null){
this.cmp = new Cmp<T>();
}
}
public void enqueue(int k, T t){
//System.out.println("k = " + k);
k++;//使得关联的整数可以为0
if(k > capacity){
throw new IllegalArgumentException();
}
if(qp[k] != -1){ //更新
element[k] = t;
swim(qp[k]);
sink(qp[k]);
return;
}
pq[++size] = k;
qp[k] = size; //k的索引
element[k] = t;
swim(size);
}
public int dequeue(){//删除堆顶最小值
if(size == 0){
throw new IllegalArgumentException();
}
int r = pq[1];
element[r] = null;
swap(pq, size, 1);
swap(qp, pq[size], pq[1]);
pq[size] = -1;
size--;
sink(1); //恢复堆有序
r--; //使得关联的整数可以为0
return r;
}
public void change(int k, T t){
//System.out.println("k1 = " + k);
k++; //使得关联的整数可以为0
if(qp[k] == -1){
throw new IllegalArgumentException();
}
element[k] = t;
swim(qp[k]);
sink(qp[k]);
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
public boolean contains(int v){
v++;//使得关联的整数可以为0
for(int i = 1; i <= size; i++)
if(pq[i] == v) return true;
return false;
}
@SuppressWarnings("unchecked")
private void swim(int child){
int parent = child/2;
while(parent > 0){
if(cmp.compare((T)element[pq[child]], (T)element[pq[parent]]) < 0){
swap(pq, child, parent);
swap(qp, pq[child], pq[parent]);
child = parent;
parent = child/2;
}else{
break;
}
}
}
@SuppressWarnings("unchecked")
private void sink(int parent){
int child = parent*2;
while(child <= size){
if(child + 1 <= size){
int r = cmp.compare((T)element[pq[child]], (T)element[pq[child+1]]);
child = r > 0 ? child+1 : child;
}
if(cmp.compare((T)element[pq[child]], (T)element[pq[parent]]) < 0){
swap(pq, parent, child);
swap(qp, pq[parent], pq[child]);
parent = child;
child = parent*2;
}else{
break;
}
}
}
public static void main(String[] args){
/* IndexMinPQ<String> ipq = new IndexMinPQ<String>(11, null);
ipq.enqueue(0, "k");
ipq.enqueue(6, "d");
ipq.enqueue(3, "f");
ipq.enqueue(4, "c");
ipq.enqueue(0, "a");
while(!ipq.isEmpty()){
System.out.println(ipq.dequeue());
}*/
IndexMinPQ<Double> ipq2 = new IndexMinPQ<Double>(11, null);
ipq2.enqueue(0, 0.10);
ipq2.enqueue(6, 0.80);
ipq2.enqueue(3, 0.76);
ipq2.enqueue(4, 0.45);
ipq2.enqueue(5, 0.96);
System.out.println(ipq2.contains(-1));
ipq2.change(6, 0.99);
while(!ipq2.isEmpty()){
System.out.println(ipq2.dequeue());
}
}
}
2.有向图的最短路径Dijkstra算法
Java实现代码:
package algorithms.graph;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Deque;
import java.util.LinkedList;
import algorithms.rank.IndexMinPQ;
/*
* 最短路径
* */
public class DijkstraSP {
private DirectedEdge[] edgeTo;
private double[] distTo;
private IndexMinPQ<Double> pq;
public DijkstraSP(EdgeWeightedDigraph G, int s){
edgeTo = new DirectedEdge[G.V()];
distTo = new double[G.V()];
for(int v = 0; v < G.V(); v++)
distTo[v] = Double.POSITIVE_INFINITY;
pq = new IndexMinPQ<Double>(G.V()+1, null);
distTo[s] = 0.0;
pq.enqueue(s, 0.00);
while(!pq.isEmpty()){
relax(G, pq.dequeue());
}
}
public void relax(EdgeWeightedDigraph G, int v){
for(DirectedEdge e : G.adj(v)){
int w = e.to();
if(distTo[v] + e.weight() < distTo[w]){
distTo[w] = distTo[v] + e.weight();
edgeTo[w] = e;
if(pq.contains(w)) pq.change(w, distTo[w]);
else pq.enqueue(w, distTo[w]);
}
}
}
public Double distTo(int v){
BigDecimal bg = new BigDecimal(distTo[v]);
double d3 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
return d3;
}
public boolean hasPathTo(int v){
return distTo[v] < Double.POSITIVE_INFINITY;
}
public Iterable<DirectedEdge> pathTo(int v){
if(!hasPathTo(v)) return null;
Deque<DirectedEdge> dq = new LinkedList<DirectedEdge>();
for(DirectedEdge e = edgeTo[v]; e != null; e = edgeTo[e.from()])
dq.push(e);
return dq;
}
public static void main(String[] args) throws IOException {
In in = new In("D:\\tinyEWD.txt");
System.out.println("图文件:");
for(String v : in.getStr())
System.out.print(v + " ");
System.out.println();
System.out.println("图邻接表:");
EdgeWeightedDigraph EWD = new EdgeWeightedDigraph(in);
System.out.println(EWD);
DijkstraSP sp = new DijkstraSP(EWD, 0);
System.out.println("起点到每个顶点的最短路径:");
for(int v = 0; v < EWD.V(); v++){
System.out.print("0到达" + v + "的最短路径: ");
System.out.print("0-");
for(DirectedEdge e : sp.pathTo(v))
System.out.print(e.to() + "-");
System.out.println(" 总路径 " + sp.distTo(v));
}
}
}
输出:
图文件:
8 15 4 5 0.35 5 4 0.35 4 7 0.37 5 7 0.28 7 5 0.28 5 1 0.32 0 4 0.38 0 2 0.26 7 3 0.39 1 3 0.29 2 7 0.34 6 2 0.40 3 6 0.52 6 0 0.58 6 4 0.93
图邻接表:
0 : 0-2 0.26 0-4 0.38
1 : 1-3 0.29
2 : 2-7 0.34
3 : 3-6 0.52
4 : 4-7 0.37 4-5 0.35
5 : 5-1 0.32 5-7 0.28 5-4 0.35
6 : 6-4 0.93 6-0 0.58 6-2 0.40
7 : 7-3 0.39 7-5 0.28
起点到每个顶点的最短路径:
0到达0的最短路径: 0- 总路径 0.0
0到达1的最短路径: 0-4-5-1- 总路径 1.05
0到达2的最短路径: 0-2- 总路径 0.26
0到达3的最短路径: 0-2-7-3- 总路径 0.99
0到达4的最短路径: 0-4- 总路径 0.38
0到达5的最短路径: 0-4-5- 总路径 0.73
0到达6的最短路径: 0-2-7-3-6- 总路径 1.51
0到达7的最短路径: 0-2-7- 总路径 0.6
任意起点的最短路径:`
package algorithms.graph;
import java.io.IOException;
/*
* 任意起点的最短路径
* */
public class DijkstraAllPairsSP {
private DijkstraSP[] all;
public DijkstraAllPairsSP(EdgeWeightedDigraph G){
all = new DijkstraSP[G.V()];
for(int v = 0; v < G.V(); v++)
all[v] = new DijkstraSP(G, v);
}
public Iterable<DirectedEdge> path(int v, int w){
return all[v].pathTo(w);
}
public double dist(int v, int w){
return all[v].distTo(w);
}
public static void main(String[] args) throws IOException {
In in = new In("D:\\tinyEWD.txt");
System.out.println("图邻接表:");
EdgeWeightedDigraph EWD = new EdgeWeightedDigraph(in);
System.out.println(EWD);
DijkstraAllPairsSP sp = new DijkstraAllPairsSP(EWD);
System.out.println("顶点2到6的最短路径:");
for(DirectedEdge e : sp.path(2,6))
System.out.print(e +" ");
System.out.print(" ,长度:"+ sp.dist(2, 6));
}
}
输出:
图邻接表:
0 : 0-2 0.26 0-4 0.38
1 : 1-3 0.29
2 : 2-7 0.34
3 : 3-6 0.52
4 : 4-7 0.37 4-5 0.35
5 : 5-1 0.32 5-7 0.28 5-4 0.35
6 : 6-4 0.93 6-0 0.58 6-2 0.40
7 : 7-3 0.39 7-5 0.28
顶点2到6的最短路径:
2-7 0.34 7-3 0.39 3-6 0.52 ,长度:1.25