019有向图的最短路径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  

顶点26的最短路径:
2-7 0.34 7-3 0.39 3-6 0.52  ,长度:1.25
### 回答1: Dijkstra算法是一种用于有向图最短路径算法。使用邻接矩阵实现Dijkstra算法的步骤如下: 1. 初始化:将起点到各个顶点的距离初始化为无穷大,将起点到自身的距离初始化为0。 2. 选择起点:从未处理的顶点中选择距离起点最近的顶点作为当前顶点。 3. 更新距离:对于当前顶点的所有邻接点,如果从起点到当前顶点再到邻接点的距离小于起点到邻接点的距离,则更新起点到邻接点的距离。 4. 标记已处理:将当前顶点标记为已处理。 5. 重复步骤2-4,直到所有顶点都被标记为已处理或者没有可达的顶点。 6. 输出结果:输出起点到各个顶点的最短距离。 邻接矩阵实现Dijkstra算法的时间复杂度为O(n^2),其中n为顶点数。 ### 回答2: 邻接矩阵是一种表示图结构的方法,具体而言,若图G有n个顶点,则邻接矩阵是一个n x n矩阵,其中每个元素表示两个顶点之间的边。在有向图中,若从顶点i到顶点j有一条有向边,则邻接矩阵中第i行第j列的元素为1,否则为0。 Dijkstra算法是一种经典的最短路径算法,它可以在带权有向图中求出从一个起点到所有其他点的最短路径Dijkstra算法的基本思想是,维护一个待访问的顶点集合V,初始时只包含起点。对于V中的每个顶点,记录起点到该顶点的最短路径长度以及已确定最短路径的所有顶点。在每一轮中,选择V中距离起点最近的顶点u,并将其加入已确定最短路径的集合S。然后,对于u的所有邻居v,如果通过u可以得到比当前路径更短的路径,则更新v的最短路径信息。重复上述过程,直到所有顶点都已被加入S为止。 使用邻接矩阵实现Dijkstra算法的基本思路是,定义两个数组dis和visited,分别记录起点到各个顶点的距离和该顶点是否已被访问。初始时,将起点的dis值设为0,visited值设为true。然后,遍历与起点相邻的顶点,并更新它们的dis值。在每一轮中,选择距离起点最近的未被访问的顶点u,并将visited[u]设为true。然后,依次遍历u的所有邻居v,如果通过u可以得到比当前路径更短的路径,则更新v的dis值。最后,重复进行n次循环,直到所有顶点的dis值都已确定。在实际实现中,可以借助优先队列等数据结构来加速算法的执行。 总的来说,使用邻接矩阵实现Dijkstra算法是一种简单有效的方法,它可以处理中等规模的带权有向图。然而,在处理大规模图时,邻接矩阵的空间复杂度和时间复杂度都较高,需要使用其他更高效的算法数据结构来解决。 ### 回答3: Dijkstra算法是一种常见的最短路径算法,在有向图中可以使用邻接矩阵来实现。邻接矩阵是一种二维数组,其中的元素表示两点之间的连接关系,如果两个点之间有连接,那么数组元素的值为连接的权重,否则为无穷大。 首先,需要定义一个图类,从而可以将邻接矩阵封装在内部,同时提供相应的函数来实现Dijkstra算法。如下所示: ``` class Graph: def __init__(self, V): self.V = V self.graph = [[0 for column in range(V)] for row in range(V)] def dijkstra(self, src): dist = [float('inf')] * self.V dist[src] = 0 sptSet = [False] * self.V for i in range(self.V): u = self.minDistance(dist, sptSet) sptSet[u] = True for v in range(self.V): if self.graph[u][v] > 0 and sptSet[v] == False and \ dist[v] > dist[u] + self.graph[u][v]: dist[v] = dist[u] + self.graph[u][v] self.printSolution(dist) def minDistance(self, dist, sptSet): min = float('inf') min_index = -1 for v in range(self.V): if dist[v] < min and sptSet[v] == False: min = dist[v] min_index = v return min_index def printSolution(self, dist): for node in range(self.V): print(f"Node {node} distance from source: {dist[node]}") ``` 在主函数中,首先需要创建一个图对象,然后按照邻接矩阵的方式设置图中边的权重。接着,可以调用Dijkstra算法来计算从源节点到其他所有节点的最短路径长度。最后,输出所有节点的距离值。 代码示例如下: ``` # create graph V = 9 g = Graph(V) # set vertices and edges g.graph = [[0, 4, 0, 0, 0, 0, 0, 8, 0], [4, 0, 8, 0, 0, 0, 0, 11, 0], [0, 8, 0, 7, 0, 4, 0, 0, 2], [0, 0, 7, 0, 9, 14, 0, 0, 0], [0, 0, 0, 9, 0, 10, 0, 0, 0], [0, 0, 4, 14, 10, 0, 2, 0, 0], [0, 0, 0, 0, 0, 2, 0, 1, 6], [8, 11, 0, 0, 0, 0, 1, 0, 7], [0, 0, 2, 0, 0, 0, 6, 7, 0]] # calculate shortest path g.dijkstra(0) ``` 以上就是使用邻接矩阵实现有向图最短路径Dijkstra算法的简要介绍。该算法常用于寻找两点之间的最短路径、计算网络中消息传递的时间等问题。当然,如果有向图中存在负权边,则需要使用Bellman-Ford算法来解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值