package org.exam.ch14.path;
/**
* Created by xin on 15.10.22.
*/
class DistPar { // distance and parent.items stored in sPath array
public int distance; // distance from start to this vertex
public int parentVert; // current parent of this vertex
public DistPar(int pv, int d) {
distance = d;
parentVert = pv;
}
}
class Vertex {
public char label; // label (e.g. 'A')
public boolean isInTree;
public Vertex(char lab) {
label = lab;
isInTree = false;
}
}
class Graph {
private final int MAX_VERTS = 20;
private final int INFINITY = 1000000;//足够大的值模拟看作无穷大
private Vertex vertexList[]; // list of vertices
private int adjMat[][]; // adjacency matrix
private int nVerts; // current number of vertices
private int nTree; // number of verts in tree
private DistPar[] sPath; // array for shortest-path data
private int currentVert; // current vertex
private int startToCurrent; // distance to currentVert
public Graph() {
vertexList = new Vertex[MAX_VERTS];
// adjacency matrix
adjMat = new int[MAX_VERTS][MAX_VERTS];
for (int j = 0; j < MAX_VERTS; j++) { //初始化邻接距离
for (int k = 0; k < MAX_VERTS; k++) { //
adjMat[j][k] = INFINITY; //都设为无穷大
}
}
sPath = new DistPar[MAX_VERTS];//存储最短路径
}
public void addVertex(char lab) {//添加顶点
vertexList[nVerts++] = new Vertex(lab);
}
public void addEdge(int start, int end, int weight) {//设置距离(单向即为有向)
adjMat[start][end] = weight;
}
public void path(int startTree) {// find all shortest paths
vertexList[startTree].isInTree = true;从顶点startTree开始,并将顶点加入到树中
nTree = 1; //树中顶点的个数
for(int j=0; j<nVerts; j++){//transfer row of distances from adjMat to sPath
int tempDist = adjMat[startTree][j];
sPath[j] = new DistPar(startTree, tempDist);
}
while (nTree < nVerts) {//直到所有顶点都已放入树
int indexMin = getMin(); //从当前顶点到各顶点获取最小路径,将这个顶点的索引返回
int minDist = sPath[indexMin].distance;//获取当前顶点到此顶点的距离
if (minDist == INFINITY) {//if all infinite or in tree,
//System.out.println("There are unreachable vertices");
break; // sPath is complete
} else { //将此顶点置为当前顶点
currentVert = indexMin; // to closest vert
startToCurrent = minDist;// minimum distance from startTree is to currentVert, and is startToCurrent
}
//将当前顶点放入树中
vertexList[currentVert].isInTree = true;
nTree++;
//将此顶点置为当前顶点后,调校最小距离,完成一次循环
adjust_sPath();
}
displayPaths(); //打印显示最终结果
nTree = 0; //重置。清除树
for(int j=0; j<nVerts; j++) {
vertexList[j].isInTree = false;
}
}
private void displayPaths() {//显示格式如: A=inf(A) B=50(A) C=100(D) D=80(A) E=140(C)
for (int j = 0; j < nVerts; j++){
System.out.print(vertexList[j].label + "=");
if (sPath[j].distance == INFINITY) {
System.out.print("inf");
} else {
System.out.print(sPath[j].distance);
}
char parent = vertexList[sPath[j].parentVert].label;
System.out.print("(" + parent + ") ");
}
System.out.println("");
}
private void adjust_sPath() { // adjust values in shortest-path array sPath
int column = 1; //跳过起点(这个column可看作表14。2的列,而每一步可看作是表的行),column是从0开始的
while (column < nVerts) { //一个一个顶点去迭代
if (vertexList[column].isInTree) {//如果此顶点已在树中,跳过
column++;
continue;
}
int currentToFringe = adjMat[currentVert][column];//计算currentVert顶点到column顶点的距离
int startToFringe = startToCurrent + currentToFringe;//从起点到column顶点的距离
int sPathDist = sPath[column].distance;//从sPath数组获取对应起点到column顶点的距离
if (startToFringe < sPathDist) { // 如果startToFringe距离是更小,重新保存到sPath数组
sPath[column].parentVert = currentVert;
sPath[column].distance = startToFringe;
}
column++;//迭代下一个顶点,看一下是否有必要调整
}
}
private int getMin() {//get entry from sPath with minimum distance
int minDist = INFINITY; //assume minimum
int indexMin = 0;
for (int j = 1; j < nVerts; j++) { // 对于每个顶点,它不在树中,并且与前一个顶点的距离比较都还要小,就更新下最小值
if (!vertexList[j].isInTree && sPath[j].distance < minDist) {
minDist = sPath[j].distance;
indexMin = j;
}
}
return indexMin;//返回最小距离顶点的索引
}
}
public class App {
public static void main(String[] args) {
Graph theGraph = new Graph();
theGraph.addVertex('A'); // 0 (start)
theGraph.addVertex('B'); // 1
theGraph.addVertex('C'); // 2
theGraph.addVertex('D'); // 3
theGraph.addVertex('E'); // 4
theGraph.addEdge(0, 1, 50); // AB 50
theGraph.addEdge(0, 3, 80); // AD 80
theGraph.addEdge(1, 2, 60); // BC 60
theGraph.addEdge(1, 3, 90); // BD 90
theGraph.addEdge(2, 4, 40); // CE 40
theGraph.addEdge(3, 2, 20); // DC 20
theGraph.addEdge(3, 4, 70); // DE 70
theGraph.addEdge(4, 1, 50); // EB 50
System.out.println("Shortest paths");
for (int i = 0; i < 5; i++) {
System.out.print(i+":");
theGraph.path(i);
}
System.out.println();
}
}