算法-最短路径算法(迪杰斯特拉算法 Dijkstra`s algorithm)

92 篇文章 0 订阅
12 篇文章 0 订阅

Dijkstra`s algorithm

概述

  • 迪杰斯特拉算法(Dijkstra`s algorithm)是最短路径算法, 用于计算一个节点到其它节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想), 直到扩展到终点为止

最短路径问题

  1. 战争时期, 胜利乡有7个村庄(A,B,C,D,E,F,G), 现在有六个邮差, 从 G点出发, 需要分别把邮件分别送到 A,B,C,D,E,F,G六个村庄
  2. 各个村庄的距离用边线权值来表示, 比如 A-B距离5公里
  • 计算出 G村庄到其它各个村庄的最短距离

在这里插入图片描述

  • 代码实现

public class DijkstraAlgorithmApp {
    /** 定义顶点*/
    private static final char[] vertexes = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
    /** 定义常量, 9999表示某顶点间不连通*/
    private static final int N = 9999;
    public static void main(String[] args) {
        /** 设置邻接矩阵的顶点与顶点间的边(附带权值)*/
        int[][] matrix = new int[vertexes.length][vertexes.length];
        matrix[0] = new int[]{N, 5, 7, N, N, N, 2};
        matrix[1] = new int[]{5, N, N, 9, N, N, 3};
        matrix[2] = new int[]{7, N, N, N, 8, N, N};
        matrix[3] = new int[]{N, 9, N, N, N, 4, N};
        matrix[4] = new int[]{N, N, 8, N, N, 5, 4};
        matrix[5] = new int[]{N, N, N, 4, 5, N, 6};
        matrix[6] = new int[]{2, 3, N, N, 4, 6, N};
        Graph graph = new Graph(vertexes, matrix);
        /** 打印邻接矩阵*/
        graph.showGraph();
        /** 求出最短路径*/
        graph.dijkstra(2); // C
        /** 打印结果*/
        graph.showDijkstra();
    }
}

class Graph {
    /** 顶点个数*/
    private char[] vertexes;
    /** 邻接矩阵*/
    private int[][] matrix;
    /** 已访问过的顶点集合*/
    private VisitedVertex visitedVertex;
    public Graph(char[] vertexes, int[][] matrix) {
        this.vertexes = vertexes;
        this.matrix = matrix;
    }

    /** 打印邻接矩阵*/
    public void showGraph() {
        for (int[] link : matrix) {
            System.out.println(Arrays.toString(link));
        }
    }

    /** 打印结果*/
    public void showDijkstra() {
        visitedVertex.show();
    }

    /** 求出最短路径(通过迪杰斯特拉算法实现的)
     * @param index 起始顶点下标*/
    public void dijkstra(int index) {
        visitedVertex = new VisitedVertex(vertexes, index);
        /** 更新 index顶点到周围顶点的距离和前驱顶点*/
        update(index);
        for(int j = 1; j <vertexes.length; j++) {
            /** 选择并返回新的访问顶点*/
            index = visitedVertex.selectNewVertex();
            /** 更新 index顶点到周围顶点的距离和前驱顶点*/
            update(index);
        }
    }

    /** 更新 index顶点到周围顶点的距离, 同时更新周围顶点的前驱顶点*/
    private void update(int index) {
        int distance = 0;
        /** 按行遍历邻接矩阵*/
        for(int j = 0; j < matrix[index].length; j++) {
            /** 出发顶点到 index顶点的距离 + 从 index顶点到 j顶点的距离的和*/
            distance = visitedVertex.getDistance(index) + matrix[index][j];
            /** 当 j顶点未被访问过, 且 distance小于出发顶点到 j顶点的距离时*/
            if(!visitedVertex.in(j) && distance < visitedVertex.getDistance(j)) {
                /** 更新 j顶点的前驱顶点为 index*/
                visitedVertex.updatePrecursor(j, index);
                /** 更新出发顶点到 j顶点的距离*/
                visitedVertex.updateDistance(j, distance);
            }
        }
    }
}

/** 定义已访问过的顶点集合类*/
class VisitedVertex {
    /** 定义顶点*/
    public char[] vertexes;
    /** 记录各个顶点是否被访问过 [1已访问, 0未访问], 会动态更新*/
    public int[] already_visited;
    /** 记录指定顶点的前驱顶点下标, 未访问和自己是0否则指定顶点下标, 会动态更新*/
    public int[] pre_visited;
    /** 记录出发顶点到其它所有顶点的最短距离(到自身为0), 会动态更新*/
    public int[] distance;

    /**
     * @param vertexes: 顶点数组
     * @param index: 起始顶点对应的下标, 比如指定 G顶点就是6*/
    public VisitedVertex(char[] vertexes, int index) {
        this.vertexes = vertexes;
        this.already_visited = new int[vertexes.length];
        this.pre_visited = new int[vertexes.length];
        this.distance = new int[vertexes.length];
        /** 初始化, 将 dis的所有元素填充 9999*/
        Arrays.fill(distance, 9999);
        /** 将起始顶点标记为已访问*/
        this.already_visited[index] = 1;
        /** 将起始顶点(自己), 距离设置为0*/
        this.distance[index] = 0;
    }

    /** 判断指定顶点是否被访问过( index为顶点下标)*/
    public boolean in(int index) {
        return already_visited[index] == 1;
    }

    /** 更新出发顶点到指定顶点的距离( index为顶点下标)*/
    public void updateDistance(int index, int distance) {
        this.distance[index] = distance;
    }

    /** 更新 index顶点的前驱顶点为 preIndex*/
    public void updatePrecursor(int index, int preIndex) {
        pre_visited[index] = preIndex;
    }

    /** 返回出发顶点到 index顶点的距离*/
    public int getDistance(int index) {
        return distance[index];
    }

    /** 筛选出, 未被访问的顶点(权值最小的), 然后返回*/
    public int selectNewVertex() {
        int min = 9999, index = 0;
        for(int i = 0; i < already_visited.length; i++) {
            if(already_visited[i] == 0 && distance[i] < min) {
                min = distance[i];
                index = i;
            }
        }
        /** 将 index顶点标记为已访问*/
        already_visited[index] = 1;
        return index;
    }

    /** 打印结果*/
    public void show() {
        System.out.println("------------------------------");
        // 输出 already_visited
        for(int i: already_visited) {
            System.out.print(i + " ");
        }
        System.out.println();

        // 输出 pre_visited
        for(int i: pre_visited) {
            System.out.print(i + " ");
        }
        System.out.println();

        // 输出 distance
        for(int i: distance) {
            System.out.print(i + " ");
        }
        System.out.println();

        int index = 0;
        for(int i: distance) {
            if (i != 9999) {
                System.out.print(vertexes[index] + "(" + i + ") ");
            } else {
                System.out.println("N ");
            }
            index++;
        }
        System.out.println();
    }

}

输出:
[9999, 5, 7, 9999, 9999, 9999, 2]
[5, 9999, 9999, 9, 9999, 9999, 3]
[7, 9999, 9999, 9999, 8, 9999, 9999]
[9999, 9, 9999, 9999, 9999, 4, 9999]
[9999, 9999, 8, 9999, 9999, 5, 4]
[9999, 9999, 9999, 4, 5, 9999, 6]
[2, 3, 9999, 9999, 4, 6, 9999]
------------------------------
1 1 1 1 1 1 1 
2 0 0 5 2 4 0 
7 12 0 17 8 13 9 
A(7) B(12) C(0) D(17) E(8) F(13) G(9) 

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值