第十四章:常用的十大算法

14.8迪杰斯特拉算法(Dijkstra)

Dijkstra算法介绍:
迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个结点到其他结点的最短路径。它的主要特点是以 起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止

Dijkstra算法思路:
1、 设置出发顶点为 v,顶点集合 V{v1,v2,vi…},v 到 V 中各顶点的距离构成距离集合 Dis,Dis{d1,d2,di…},Dis 集合记录着 v 到图中各顶点的距离(到自身可以看作 0,v 到 vi距离对应为di)
2、 从 Dis 中选择值最小的 di 并移出 Dis 集合,同时移出 V 集合中对应的顶点 vi,此时的 v 到 vi 即为最短路径
3、 更新 Dis 集合,更新规则为:比较 v 到 V 集合中顶点的距离值,与 v 通过 vi 到 V 集合中顶点的距离值,保留 值较小的一个(同时也应该更新顶点的前驱节点为 vi,表明是通过 vi 到达的)
4、 重复执行两步骤,直到最短路径顶点为目标顶点即可结束

Dijkstra算法应用:寻找指定村庄到其他各个村庄的最短路径问题
在这里插入图片描述
在这里插入图片描述

package com.atguigu21.dijkstra;

import java.util.Arrays;

/**
 * @author peng
 * @date 2021/12/7 - 11:23
 */
public class DijkstraAlgorithm {
    public static void main(String[] args) {
        char[] vertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        final int N = 65535;
        int[][] matrix = new int[vertex.length][vertex.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(vertex, matrix);
        graph.showGraph();
        graph.dis(6);
        graph.showDijkstra();
    }
}

/**
 * 创建已访问结点的集合
 */
class VisitedVertexs {
    public int[] alread_arr;//记录每个结点是否已经访问过,如果访问过就置为1, 没有访问过就是0
    public int[] pre_visited;//记录每一个结点对应的前一个结点的下标,也就是每一个结点的前驱结点
    public int[] dis;//记录出发顶点到其它结点的距离,比如:假设出发顶点是G,那么dis保留的就是G到其它结点的距离

    /**
     * @param length:表示顶点的个数
     * @param index:表示出发顶点的坐标
     */
    public VisitedVertexs(int length, int index) {
        this.alread_arr = new int[length];
        this.pre_visited = new int[length];
        this.dis = new int[length];

        //初始化距离
        Arrays.fill(dis, 65535);//表示刚开始的时候,所有点之间的距离都是65535
        dis[index] = 0;//表示自己到自己的距离是0,并不是65535
        this.alread_arr[index] = 1;//当前结点一进来就表示已经遍历了,所以要置为1
    }

    /**
     * 判断index这个顶点是否已经访问过,访问过就是true,没有访问过就是false
     *
     * @param index
     * @return
     */
    public boolean ifVisited(int index) {
        return alread_arr[index] == 1;
    }

    /**
     * 更新出发顶点到index的距离
     *
     * @param inedx
     * @param len
     */
    public void updateDis(int inedx, int len) {
        dis[inedx] = len;
    }

    /**
     * 将顶点pre的前驱更新为index
     *
     * @param pre
     * @param index
     */
    public void updatePre(int pre, int index) {
        pre_visited[pre] = index;
    }

    /**
     * 返回出发顶点到index的距离
     *
     * @param index
     */
    public int getDis(int index) {
        return dis[index];
    }

    /**
     * 继续选择并返回新的访问结点,比如题目的G结点访问结束后,A就作为了新的访问结点
     *
     * @return
     */
    public int updateArr() {
        int min = 65535, index = 0;
        for (int i = 0; i < alread_arr.length; i++) {
            if (alread_arr[i] == 0 && dis[i] < min) {
                //如果发现了新的更加短的路径
                index = i;
                min = dis[i];
            }
        }
        alread_arr[index] = 1;
        return index;
    }

    /**
     * 输出最后的结果
     */
    public void show() {
        for (int row : alread_arr) {
            System.out.print(row + "\t");
        }
        System.out.println();
        for (int value : pre_visited) {
            System.out.print(value + "\t");
        }
        System.out.println();
        for (int value : dis) {
            System.out.print(value + "\t");
        }
    }
}

/**
 * 创建图
 */
class Graph {
    private char[] vertex;//图的顶点
    private int[][] matrix;//二维数组
    private VisitedVertexs vv;//已经访问过的顶点的集合

    public Graph(char[] vertex, int[][] matrix) {
        this.vertex = vertex;
        this.matrix = matrix;
    }

    /**
     * 输出图
     */
    public void showGraph() {
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
    }

    /**
     * 实现迪杰斯特拉算法
     *
     * @param index
     */
    public void dis(int index) {
        vv = new VisitedVertexs(vertex.length, index);
        update(index);
        for (int i = 1; i < vertex.length; i++) {
            //因为顶点已经进去了,所以从下一个点开始
            index = vv.updateArr();
            update(index);
        }
    }

    /**
     * 应该说是:统计从开始结点到当前index结点所有的距离之和并更新当前结点的前驱结点
     *
     * @param index
     */
    public void update(int index) {
        int len = 0;
        //遍历index结点对应的行
        for (int i = 0; i < matrix[index].length; i++) {
            //vv.getDis(index):表示当前结点之前,已经走过的距离
            //matrix[index][i]:表示当前结点到下一个结点的距离
            len = vv.getDis(index) + matrix[index][i];
            if (!vv.ifVisited(i) && len < vv.getDis(i)) {
                //如果发现这一条新的路,比原来的那一条路还要近,就要用新路去替换旧路
                vv.updateDis(i, len);//更新出发顶点到i的距离
                vv.updatePre(i, index);//将i结点的前驱更改为index
            }
        }
    }

    public void showDijkstra() {
        vv.show();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值