迪杰斯特拉算法

Java控制台程序,打印的语句很多,直接看控制台输出更好理解。

package com.company;

public class Main {

    public static void main(String[] args) {
    // write your code here
        int[][] testMatrix = {
                {-1,-1,10,-1,30,100},
                {-1,-1,5,-1,-1,-1},
                {-1,-1,-1,50,-1,-1},
                {-1,-1,-1,-1,0,10},
                {-1,-1,-1,20,-1,60},
                {-1,-1,-1,-1,-1,-1}
        };
        Dijkstra.dijkstra0(testMatrix,0);
    }
}

package com.company;

public class Dijkstra {
    /**
     * 这就是著名的迪杰斯特拉算法,适用于有向图。
     * 求的是某源点到所有其他顶点的最短路径问题。
     * 从算法的变化图来看,该算法就是在已经找到最
     * 短路径的顶点集合之外一个顶点,该顶点与已有
     * 集合的顶点邻接,并且,邻接的边加上该集合中
     * 邻接的点的最短路径以后最小的那个非该集合的
     * 顶点加入到该集合中。
     * 这是贪心算法思想的典型代表。
     * 本实现的打印语句比较多,为的是直观地展现该
     * 算法思想。
     * @param sourceArray
     * @param vertexId
     */
    static public void dijkstra0(int[][] sourceArray,int vertexId) {
        int arrayLength = sourceArray.length;
        if (vertexId < 0 || vertexId > arrayLength - 1) {
            System.out.println("输入顶点编号超出范围");
            return;
        }
        //获取相对的最大值
        int maxValue = 0;
        for (int counter = 0;counter < arrayLength;counter++) {
            for (int counter0 = 0;counter0 < arrayLength;counter0++) {
                if (sourceArray[counter][counter0] < 0)continue;
                else maxValue += sourceArray[counter][counter0];
            }
        }
        //用来存储每个顶点的前驱顶点。
        int[] preVertextArray = new int[arrayLength];
        for (int counter = 0;counter < arrayLength;counter++)
            preVertextArray[counter] = -1;
        //这个用来表示已经找到最小路径的顶点集。
        VertexPath[] minPathArray = new VertexPath[arrayLength];
        int minPathPointer = 0;
        //没有找到最小路径的顶点集合。
        VertexPath[] equivocalVertexArray = new VertexPath[arrayLength];
        int equivocalVertexPointer = 0;
        //首先初始化没有找到最小路径的顶点集合,顺便把前驱数组初始化一下。
        for (int counter = 0;counter < arrayLength;counter++) {
            if (vertexId == counter) {
                equivocalVertexArray[equivocalVertexPointer++] =
                        new VertexPath(counter,0);
                preVertextArray[vertexId] = -1;
            }
            else {
                equivocalVertexArray[equivocalVertexPointer++] =
                        new VertexPath(counter,sourceArray[vertexId][counter]);
                if (sourceArray[vertexId][counter] > 0)
                    preVertextArray[counter] = vertexId;
            }
        }
        //首先从还没有找到最短路径的集合中找到不是-1的也
        // 不是maxValue的顶点,因为这些顶点是和已有最短
        // 路径点集直接相连的顶点。从这些点中选择权值最小
        // 的那个,添加到已有最短路径点集中。直到已有最短
        // 路径点集满,出现maxValue或者-1权值的顶点为止。
        while (minPathPointer < arrayLength) {
            System.out.println("已有最小顶点的最小顶点序列");
            for (int counter = 0;counter < minPathPointer;counter++) {
                System.out.print("<" + minPathArray[counter].getVertexId() + "," + minPathArray[counter].getMinPathLenght() + ">");
            }
            System.out.println("\n没有选出最小顶点之前的非最小路径顶点序列");
            for (int counter = 0;counter < equivocalVertexPointer;counter++) {
                System.out.print("<" + equivocalVertexArray[counter].getVertexId() + "," + equivocalVertexArray[counter].getMinPathLenght() + ">");
            }
            System.out.println("\n即将刷新");
            int firstMaxValue = maxValue;
            int minVertexPointer = 0;
            //找出没有最短路径的点集中的最小权的顶点。
            for (int counter = 0;counter < equivocalVertexPointer;counter++) {
                if (equivocalVertexArray[counter].getMinPathLenght() >= 0 &&
                        equivocalVertexArray[counter].getMinPathLenght() < firstMaxValue) {
                    minVertexPointer = counter;
                    firstMaxValue = equivocalVertexArray[counter].getMinPathLenght();
                }
            }
            //然后和没有最短路径的数组的大边界元素交换
            // ,这样做的好处是可以节省空间和避免不必要的遍历。
            if (minVertexPointer != equivocalVertexPointer - 1) {
                VertexPath tempNode = equivocalVertexArray[equivocalVertexPointer - 1];
                equivocalVertexArray[equivocalVertexPointer - 1] = equivocalVertexArray[minVertexPointer];
                equivocalVertexArray[minVertexPointer] = tempNode;
            }
            minPathArray[minPathPointer] = equivocalVertexArray[equivocalVertexPointer - 1];
            minPathPointer++;
            equivocalVertexPointer--;
            System.out.println("已经选出的最小顶点序列");
            for (int counter = 0;counter < minPathPointer;counter++) {
                System.out.print("<" + minPathArray[counter].getVertexId() + "," + minPathArray[counter].getMinPathLenght() + ">");
            }
            System.out.println("\n调整之前的非最小路径定点");
            for (int counter = 0;counter < equivocalVertexPointer;counter++) {
                System.out.print("<" + equivocalVertexArray[counter].getVertexId() + "," + equivocalVertexArray[counter].getMinPathLenght() + ">");
            }
            System.out.println();
            //已有最短路径的顶点集
            for (int counter = 0;counter < minPathPointer && minPathArray[counter].getMinPathLenght() >= 0;counter++) {
                System.out.println("现在依据<" + minPathArray[counter].getVertexId() +
                        "," + minPathArray[counter].getMinPathLenght() + ">进行刷新");
                //还没有最短路径的顶点集合。
                for (int counter0 = 0;counter0 < equivocalVertexPointer;counter0++) {
                    System.out.println("现在调整未调整的顶点<" + equivocalVertexArray[counter0].getVertexId() +
                            "," + equivocalVertexArray[counter0].getMinPathLenght() + ">");
                    //这是相临边,有可能是无限大的,此时直接跳过,
                    // 不过这里处于打印的需要,我还是写了else。
                    int edgeLength = sourceArray[minPathArray[counter].getVertexId()]
                            [equivocalVertexArray[counter0].getVertexId()];
                    //此时为可达的情况下,也就是有相邻的边的时候。
                    if (edgeLength > 0) {
                        System.out.println("可达边长度为:" + edgeLength);
                        //因为这里认为边权为负代表无穷大。
                        if (equivocalVertexArray[counter0].getMinPathLenght() < 0)
                            equivocalVertexArray[counter0].setMinPathLenght(maxValue);
                        if (edgeLength + minPathArray[counter].getMinPathLenght() <
                                equivocalVertexArray[counter0].getMinPathLenght()) {
                            //找到更小的就更新边权值
                            System.out.println(edgeLength + " + " + minPathArray[counter].getMinPathLenght()
                                    + "小于" + equivocalVertexArray[counter0].getMinPathLenght());
                            preVertextArray[equivocalVertexArray[counter0].getVertexId()]
                                    = minPathArray[counter].getVertexId();
                            equivocalVertexArray[counter0].setMinPathLenght(edgeLength
                                    + minPathArray[counter].getMinPathLenght());
                            System.out.println("顶点" + equivocalVertexArray[counter0].getVertexId()
                                    + "权被更新为" + (edgeLength
                                    + minPathArray[counter].getMinPathLenght()));
                        } else {
                            System.out.println(edgeLength + " + " + minPathArray[counter].getMinPathLenght()
                                    + "与" + equivocalVertexArray[counter0].getMinPathLenght() + "相比");
                            System.out.println("没使路径更小,舍去!");
                        }
                    } else System.out.println("不可达");
                }
            }
            System.out.println("调整之后的最小路径顶点");
            for (int counter = 0;counter < minPathPointer;counter++) {
                System.out.print("<" + minPathArray[counter].getVertexId() + "," + minPathArray[counter].getMinPathLenght() + ">");
            }
            System.out.println("\n调整之后的非最小路径定点");
            for (int counter = 0;counter < equivocalVertexPointer;counter++) {
                System.out.print("<" + equivocalVertexArray[counter].getVertexId() + "," + equivocalVertexArray[counter].getMinPathLenght() + ">");
            }
            System.out.println("\n结束刷新\n");
        }
        System.out.println("结果集为:");
        int[] pathStack = new int[arrayLength];
        for (int counter = 0;counter < arrayLength;counter++) {
            if (counter == vertexId)continue;
            int pathStackTopPointer = -1;
            int preIndex = counter;
            while (preVertextArray[preIndex] >= 0) {
                pathStack[++pathStackTopPointer] = preIndex;
                preIndex = preVertextArray[preIndex];
            }
            pathStack[++pathStackTopPointer] = preIndex;
            System.out.print("(" + vertexId + "," + counter + "):");
            if (pathStack[pathStackTopPointer] != vertexId)
                System.out.print("不可达");
            else {
                while (pathStackTopPointer > -1) {
                    if (counter == pathStack[pathStackTopPointer])
                        System.out.print(pathStack[pathStackTopPointer--]);
                    else System.out.print(pathStack[pathStackTopPointer--] + "-->");
                }
            }
            System.out.println();
        }
    }
}

package com.company;

public class VertexPath {
    private int vertexId;
    private int minPathLenght;

    public VertexPath(int vertexId, int minPathLenght) {
        this.vertexId = vertexId;
        this.minPathLenght = minPathLenght;
    }

    public int getMinPathLenght() {
        return minPathLenght;
    }

    public void setMinPathLenght(int minPathLenght) {
        this.minPathLenght = minPathLenght;
    }

    public int getVertexId() {
        return vertexId;
    }
}

输出

已有最小顶点的最小顶点序列

没有选出最小顶点之前的非最小路径顶点序列
<0,0><1,-1><2,10><3,-1><4,30><5,100>
即将刷新
已经选出的最小顶点序列
<0,0>
调整之前的非最小路径定点
<5,100><1,-1><2,10><3,-1><4,30>
现在依据<0,0>进行刷新
现在调整未调整的顶点<5,100>
可达边长度为:100
100 + 0与100相比
没使路径更小,舍去!
现在调整未调整的顶点<1,-1>
不可达
现在调整未调整的顶点<2,10>
可达边长度为:10
10 + 0与10相比
没使路径更小,舍去!
现在调整未调整的顶点<3,-1>
不可达
现在调整未调整的顶点<4,30>
可达边长度为:30
30 + 0与30相比
没使路径更小,舍去!
调整之后的最小路径顶点
<0,0>
调整之后的非最小路径定点
<5,100><1,-1><2,10><3,-1><4,30>
结束刷新

已有最小顶点的最小顶点序列
<0,0>
没有选出最小顶点之前的非最小路径顶点序列
<5,100><1,-1><2,10><3,-1><4,30>
即将刷新
已经选出的最小顶点序列
<0,0><2,10>
调整之前的非最小路径定点
<5,100><1,-1><4,30><3,-1>
现在依据<0,0>进行刷新
现在调整未调整的顶点<5,100>
可达边长度为:100
100 + 0与100相比
没使路径更小,舍去!
现在调整未调整的顶点<1,-1>
不可达
现在调整未调整的顶点<4,30>
可达边长度为:30
30 + 0与30相比
没使路径更小,舍去!
现在调整未调整的顶点<3,-1>
不可达
现在依据<2,10>进行刷新
现在调整未调整的顶点<5,100>
不可达
现在调整未调整的顶点<1,-1>
不可达
现在调整未调整的顶点<4,30>
不可达
现在调整未调整的顶点<3,-1>
可达边长度为:50
50 + 10小于285
顶点3权被更新为60
调整之后的最小路径顶点
<0,0><2,10>
调整之后的非最小路径定点
<5,100><1,-1><4,30><3,60>
结束刷新

已有最小顶点的最小顶点序列
<0,0><2,10>
没有选出最小顶点之前的非最小路径顶点序列
<5,100><1,-1><4,30><3,60>
即将刷新
已经选出的最小顶点序列
<0,0><2,10><4,30>
调整之前的非最小路径定点
<5,100><1,-1><3,60>
现在依据<0,0>进行刷新
现在调整未调整的顶点<5,100>
可达边长度为:100
100 + 0与100相比
没使路径更小,舍去!
现在调整未调整的顶点<1,-1>
不可达
现在调整未调整的顶点<3,60>
不可达
现在依据<2,10>进行刷新
现在调整未调整的顶点<5,100>
不可达
现在调整未调整的顶点<1,-1>
不可达
现在调整未调整的顶点<3,60>
可达边长度为:50
50 + 10与60相比
没使路径更小,舍去!
现在依据<4,30>进行刷新
现在调整未调整的顶点<5,100>
可达边长度为:60
60 + 30小于100
顶点5权被更新为90
现在调整未调整的顶点<1,-1>
不可达
现在调整未调整的顶点<3,60>
可达边长度为:20
20 + 30小于60
顶点3权被更新为50
调整之后的最小路径顶点
<0,0><2,10><4,30>
调整之后的非最小路径定点
<5,90><1,-1><3,50>
结束刷新

已有最小顶点的最小顶点序列
<0,0><2,10><4,30>
没有选出最小顶点之前的非最小路径顶点序列
<5,90><1,-1><3,50>
即将刷新
已经选出的最小顶点序列
<0,0><2,10><4,30><3,50>
调整之前的非最小路径定点
<5,90><1,-1>
现在依据<0,0>进行刷新
现在调整未调整的顶点<5,90>
可达边长度为:100
100 + 0与90相比
没使路径更小,舍去!
现在调整未调整的顶点<1,-1>
不可达
现在依据<2,10>进行刷新
现在调整未调整的顶点<5,90>
不可达
现在调整未调整的顶点<1,-1>
不可达
现在依据<4,30>进行刷新
现在调整未调整的顶点<5,90>
可达边长度为:60
60 + 30与90相比
没使路径更小,舍去!
现在调整未调整的顶点<1,-1>
不可达
现在依据<3,50>进行刷新
现在调整未调整的顶点<5,90>
可达边长度为:10
10 + 50小于90
顶点5权被更新为60
现在调整未调整的顶点<1,-1>
不可达
调整之后的最小路径顶点
<0,0><2,10><4,30><3,50>
调整之后的非最小路径定点
<5,60><1,-1>
结束刷新

已有最小顶点的最小顶点序列
<0,0><2,10><4,30><3,50>
没有选出最小顶点之前的非最小路径顶点序列
<5,60><1,-1>
即将刷新
已经选出的最小顶点序列
<0,0><2,10><4,30><3,50><5,60>
调整之前的非最小路径定点
<1,-1>
现在依据<0,0>进行刷新
现在调整未调整的顶点<1,-1>
不可达
现在依据<2,10>进行刷新
现在调整未调整的顶点<1,-1>
不可达
现在依据<4,30>进行刷新
现在调整未调整的顶点<1,-1>
不可达
现在依据<3,50>进行刷新
现在调整未调整的顶点<1,-1>
不可达
现在依据<5,60>进行刷新
现在调整未调整的顶点<1,-1>
不可达
调整之后的最小路径顶点
<0,0><2,10><4,30><3,50><5,60>
调整之后的非最小路径定点
<1,-1>
结束刷新

已有最小顶点的最小顶点序列
<0,0><2,10><4,30><3,50><5,60>
没有选出最小顶点之前的非最小路径顶点序列
<1,-1>
即将刷新
已经选出的最小顶点序列
<0,0><2,10><4,30><3,50><5,60><1,-1>
调整之前的非最小路径定点

现在依据<0,0>进行刷新
现在依据<2,10>进行刷新
现在依据<4,30>进行刷新
现在依据<3,50>进行刷新
现在依据<5,60>进行刷新
调整之后的最小路径顶点
<0,0><2,10><4,30><3,50><5,60><1,-1>
调整之后的非最小路径定点

结束刷新

结果集为:
(0,1):不可达
(0,2):0-->2
(0,3):0-->4-->3
(0,4):0-->4
(0,5):0-->4-->3-->5

你可能感兴趣的:(迪杰斯特拉算法)