MrShi
2 天以前 eb82684152ffb0acddf67da92e4533a0190eb258
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
package com.doumee.core.utils;
 
import java.util.*;
 
/**
 * 最短路径—Dijkstra算法和Floyd算法
 * Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。
 *
 * 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)
 */
 
public class GraphByMatrix {
    public static final boolean UNDIRECTED_GRAPH = false;//无向图标志
    public static final boolean DIRECTED_GRAPH = true;//有向图标志
 
    public static final boolean ADJACENCY_MATRIX = true;//邻接矩阵实现
    public static final boolean ADJACENCY_LIST = false;//邻接表实现
 
    public static final int MAX_VALUE = Integer.MAX_VALUE;
    private boolean graphType;
    private boolean method;
    private int vertexSize;
    private int matrixMaxVertex;
 
    //存储所有顶点信息的一维数组
    private Object[] vertexesArray;
    //存储图中顶点之间关联关系的二维数组,及边的关系
    private int[][] edgesMatrix;
 
    // 记录第i个节点是否被访问过
    private boolean[] visited;
 
    /**
     * @param graphType 图的类型:有向图/无向图
     * @param method    图的实现方式:邻接矩阵/邻接表
     */
    public GraphByMatrix(boolean graphType, boolean method, int size) {
        this.graphType = graphType;
        this.method = method;
        this.vertexSize = 0;
        this.matrixMaxVertex = size;
 
        if (this.method) {
            visited = new boolean[matrixMaxVertex];
            vertexesArray = new Object[matrixMaxVertex];
            edgesMatrix = new int[matrixMaxVertex][matrixMaxVertex];
 
            //对数组进行初始化,顶点间没有边关联的值为Integer类型的最大值
            for (int row = 0; row < edgesMatrix.length; row++) {
                for (int column = 0; column < edgesMatrix.length; column++) {
                    edgesMatrix[row][column] = MAX_VALUE;
                }
            }
 
        }
    }
 
    /********************最短路径****************************/
    //计算一个顶点到其它一个顶点的最短距离
    public void Dijkstra(Object obj) throws Exception {
        Dijkstra(getVertexIndex(obj));
    }
    public void Dijkstra(int v0) {
        int[] dist = new int[matrixMaxVertex];
        int[] prev = new int[matrixMaxVertex];
 
        //初始化visited、dist和path
        for (int i = 0; i < vertexSize; i++) {
            //一开始假定取直达路径最短
            dist[i] = edgesMatrix[v0][i];
            visited[i] = false;
 
            //直达情况下的最后经由点就是出发点
            if (i != v0 && dist[i] < MAX_VALUE)
                prev[i] = v0;
            else
                prev[i] = -1; //无直达路径
        }
 
        //初始时源点v0∈visited集,表示v0 到v0的最短路径已经找到
        visited[v0] = true;
 
        // 下来假设经由一个点中转到达其余各点,会近些,验证之
        // 再假设经由两个点中转,会更近些,验证之,.....
        // 直到穷举完所有可能的中转点
        int minDist;
        int v = 0;
        for (int i = 1; i < vertexSize; i++) {
            //挑一个距离最近经由点,下标装入 v
            minDist = MAX_VALUE;
 
            for (int j = 0; j < vertexSize; j++) {
                if ((!visited[j]) && dist[j] < minDist) {
                    v = j;                             // 经由顶点j中转则距离更短
                    minDist = dist[j];
                }
            }
            visited[v] = true;
 
            /*顶点v并入S,由v0到达v顶点的最短路径为min.
              假定由v0到v,再由v直达其余各点,更新当前最后一个经由点及距离*/
            for (int j = 0; j < vertexSize; j++) {
                if ((!visited[j]) && edgesMatrix[v][j] < MAX_VALUE) {
 
                    if (minDist + edgesMatrix[v][j] <= dist[j]) {
                        //如果多经由一个v点到达j点的 最短路径反而要短,就更新
                        dist[j] = minDist + edgesMatrix[v][j];
 
                        prev[j] = v;                    //经由点的序号
                    }
 
                }
            }
 
        }
 
        for (int i = 1; i < matrixMaxVertex; i++) {
            System.out.println("**" + vertexesArray[v0] + "-->" +vertexesArray[i] + " 的最短路径是:" + dist[i]);
        }
    }
 
    //获取顶点值在数组里对应的索引
    private int getVertexIndex(Object obj) throws Exception {
        int index = -1;
        for (int i = 0; i < vertexSize; i++) {
            if (vertexesArray[i].equals(obj)) {
                index = i;
                break;
            }
        }
        if (index == -1) {
            throw new Exception("没有这个值!");
        }
 
        return index;
    }
 
    /**
     * 单源最短路径算法,用于计算一个节点到其他!!所有节点!!的最短路径
     */
    public void Dijkstra2(int v0) {
        // LinkedList实现了Queue接口 FIFO
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < vertexSize; i++) {
            visited[i] = false;
        }
        List<Map<String,Object>> result = new ArrayList<>();
        //这个循环是为了确保每个顶点都被遍历到
        int lastRow =0;
        for (int i = 0; i < vertexSize; i++) {
            if (!visited[i]) {
                queue.add(i);
                visited[i] = true;
                while (!queue.isEmpty()) {
                    int row = queue.remove();
                    Map<String,Object> map = new HashMap<>();
                    map.put("name", vertexesArray[row]);
                    map.put("row", row);
                    int tempDis =0;
                    if(row>0){
                        tempDis  = edgesMatrix[lastRow][row];
                        lastRow =row;
                    }
                    map.put("dis", tempDis);
                    result.add(map);
                    System.out.print(vertexesArray[row] + "-->");
                    for (int k = getMin(row); k >= 0; k = getMin(row)) {
                        if (!visited[k]) {
                            queue.add(k);
                            visited[k] = true;
                        }
                    }
                }
            }
        }
        System.out.println("");
        int totalDis =0;
        for(Map<String,Object> c :result){
            totalDis +=  (Integer) c.get("dis");
            System.out.print( c.get("name") + "--"+c.get("dis")+"-->");
        }
        System.out.println("");
        System.out.println("最短距离"+totalDis);
    }
 
    private int getMin( int row) {
        int minDist = MAX_VALUE;
        int index = 0;
        for (int j = 0; j < vertexSize; j++) {
            if ((!visited[j]) && edgesMatrix[row][j] < minDist) {
                minDist = edgesMatrix[row][j];
                index = j;
            }
        }
        if (index == 0) {
            return -1;
        }
        return index;
    }
 
    public boolean addVertex(Object val) {
        assert (val != null);
        vertexesArray[vertexSize] = val;
        vertexSize++;
        return true;
    }
 
    public boolean addEdge(int vnum1, int vnum2, int weight) {
        assert (vnum1 >= 0 && vnum2 >= 0 && vnum1 != vnum2 && weight >= 0);
 
        //有向图
        if (graphType) {
            edgesMatrix[vnum1][vnum2] = weight;
 
        } else {
            edgesMatrix[vnum1][vnum2] = weight;
            edgesMatrix[vnum2][vnum1] = weight;
        }
 
        return true;
    }
 
    public static void main(String[] args) throws Exception {
        GraphByMatrix graph = new GraphByMatrix(GraphByMatrix.DIRECTED_GRAPH, GraphByMatrix.ADJACENCY_MATRIX, 9);
 
        graph.addVertex("A");//0
        graph.addVertex("B");//1
        graph.addVertex("C");//2
        graph.addVertex("D");//3
        graph.addVertex("E");//4
 
        //A->B、C、D
        graph.addEdge(0, 1,10);
        graph.addEdge(0, 2,5);
        graph.addEdge(0, 3,7);
        //B->C、D、E
        graph.addEdge(1, 2,4);
        graph.addEdge(1, 3,5);
        graph.addEdge(1, 4,10);
        //C->B、D、E
        graph.addEdge(2, 1,4);
        graph.addEdge(2, 3,6);
        graph.addEdge(2, 4,5);
        //D->B、C、E
        graph.addEdge(3, 1,5);
        graph.addEdge(3, 2,6);
        graph.addEdge(3, 4,7);
 
 
        graph.Dijkstra(0);
        System.out.println();
        graph.Dijkstra("C");
        System.out.println();
        graph.Dijkstra2(0);
        System.out.println();
    }
 
}