代码来自闵老师”日撸 Java 三百行(31-40天)“,链接:https://blog.youkuaiyun.com/minfanphd/article/details/116975772
Dijkstra 算法理解参考:https://zhuanlan.zhihu.com/p/129373740
Prim算法理解参考:http://c.biancheng.net/algorithm/prim.html
两种算法都是把所有点分成两类A和B,将B(未找到最短路径的集合)中的点不断的移动到A(已找到最短路径的集合)里面去。Dijkstra 算法是根据B集合里的每一个节点,到起始点的总的最短距离进行移动;Prim算法会选择当前和A集合中的节点直接相连的节点,哪个边最短进行移动。借用原博客(Prim算法)的一个图进行理解,如下:
对于Dijkstra 算法,因为B-S有多个通路:S-A,A-C,C-B(距离14); S-A,A-B(距离13);S-C,C-B(距离12);S-A,A-C,C-D,D-B(距离15);此时算法会选择通路S-C,C-B。
对于Prim算法,此时集合A里有{S,A,C,D}四个节点,B到其中每个节点的最短距离分别为12,6,4,2;此时算法会选择BD边。
package datastructure.graph;
import matrix.IntMatrix;
import java.util.Arrays;
/**
* Weight graphs are called nets.
*
* @author WX873
*
*/
public class Net {
/**
* The maximal distance. Do not use Integer.MAX_VALUE.
*/
public static final int MAX_DISTANCE = 10000;
/**
* The number of nodes.
*/
int numNodes;
/**
* The weight matrix. We use int to represent weight for simplicity.
*/
IntMatrix weightMatrix;
/**
* **********************************************************
* The first constructor of Net.
*
* @param paraNumNodes The number of nodes in the graph.
* **********************************************************
*/
public Net(int paraNumNodes) {
// TODO Auto-generated constructor stub
weightMatrix = new IntMatrix(paraNumNodes, paraNumNodes);
for (int i = 0; i < paraNumNodes; i++) {
//Fill in the maximum value for each row.
Arrays.fill(weightMatrix.getData()[i], MAX_DISTANCE);
}//of for i
}//The first constructor of Net.
/**
* ************************************************************
* The second constructor of Net.
*
* @param paraWeightMatrix The data of weight matrix.
* ************************************************************
*/
public Net(int[][] paraWeightMatrix) {
// TODO Auto-generated constructor stub
weightMatrix = new IntMatrix(paraWeightMatrix);
numNodes = paraWeightMatrix.length;
}//The second constructor of Net.
/**
* **************************************************************
* Overrides the method claimed in Object, the superclass of any class.
* **************************************************************
*/
public String toString() {
String resultString = "This is the weight matrix of the graph.\r\n" + weightMatrix;
return resultString;
}//of toString
/**
* ****************************************************************
* The Dijkstra algorithm: shortest path from the source to all nodes.
*
* @param paraSource The source node.
* @return The distances to all nodes.
* ****************************************************************
*/
public int[] dijkstra(int paraSource) {
int[] tempDistanceArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tempDistanceArray[i] = weightMatrix.getData()[paraSource][i];
}//of for i
int[] tempParentArray = new int[numNodes];
Arrays.fill(tempParentArray, paraSource);
// -1 for no parent.
tempParentArray[paraSource] = -1;
//Is it used to mark whether it has already been accessed?
boolean[] tempVisitedArray = new boolean[numNodes];
tempVisitedArray[paraSource] = true;
//Main loops.
//There are n-1 nodes in addition to paraSource. Loop n-1 times the unallocated set is empty.
int tempDistance;
int tempBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
// Step 2.1 Find out the best next node.
tempDistance = MAX_DISTANCE;
for (int j = 0; j < numNodes; j++) {
if (tempVisitedArray[j]) {
// This node is visited.
continue;
}//of if
if (tempDistanceArray[j] < tempDistance) {
tempDistance = tempDistanceArray[j];
tempBestNode = j;
}//of if
}//of for j
tempVisitedArray[tempBestNode] = true;
//Step 2.2 Prepare for the next round.
for (int j = 0; j < numNodes; j++) {
if (tempVisitedArray[j]) {
// This node is visited.
continue;
}//of if
if (tempDistanceArray[j] > MAX_DISTANCE) {
//can not reach.
continue;
}//of if
if (tempDistanceArray[j] > tempDistanceArray[tempBestNode] + weightMatrix.getData()[tempBestNode][j]) {
tempDistanceArray[j] = tempDistanceArray[tempBestNode] + weightMatrix.getData()[tempBestNode][j];
tempParentArray[j] = tempBestNode;
}//of if
}//of for j
System.out.println(tempBestNode);
}//of for i
return tempDistanceArray;
}//of dijkstra
/**
* **********************************************************************
* The minimal spanning tree.
*
* @param paraSource The source node.
* @return The total cost of the tree.
* **********************************************************************
*/
public int prim(int paraSource) {
int[] tempDistanceArray = new int[numNodes];
int resultCost = 0;
for (int i = 0; i < numNodes; i++) {
tempDistanceArray[i] = weightMatrix.getData()[paraSource][i];
}//of for i
int[] tempParentArray = new int[numNodes];
Arrays.fill(tempParentArray, paraSource);
// -1 for no parent.
tempParentArray[paraSource] = -1;
//Is it used to mark whether it has already been accessed?
boolean[] tempVisitedArray = new boolean[numNodes];
tempVisitedArray[paraSource] = true;
//Main loops.
//There are n-1 nodes in addition to paraSource. Loop n-1 times the unallocated set is empty.
int tempDistance;
int tempBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
// Step 2.1 Find out the best next node.
tempDistance = MAX_DISTANCE;
for (int j = 0; j < numNodes; j++) {
if (tempVisitedArray[j]) {
// This node is visited.
continue;
}//of if
if (tempDistanceArray[j] < tempDistance) {
tempDistance = tempDistanceArray[j];
tempBestNode = j;
}//of if
}//of for j
resultCost += tempDistanceArray[tempBestNode];
tempVisitedArray[tempBestNode] = true;
//Step 2.2 Prepare for the next round.
for (int j = 0; j < numNodes; j++) {
if (tempVisitedArray[j]) {
// This node is visited.
continue;
}//of if
if (tempDistanceArray[j] > MAX_DISTANCE) {
//can not reach.
continue;
}//of if
if (tempDistanceArray[j] > weightMatrix.getData()[tempBestNode][j]) {
tempDistanceArray[j] = weightMatrix.getData()[tempBestNode][j];
tempParentArray[j] = tempBestNode;
}//of if
//For test
//System.out.println("The selected distance for each node: " + Arrays.toString(tempDistanceArray));
}//of for j
System.out.println(tempBestNode);
}//of for i
return resultCost;
}//of prim
/**
* **********************************************************************
* The minimal spanning tree.
*
* @param paraSource The source node.
* @return The total cost of the tree.
* **********************************************************************
*/
public int prim() {
int[] tempDistanceArray = new int[numNodes];
int tempSource = 0;
int resultCost = 0;
for (int i = 0; i < numNodes; i++) {
tempDistanceArray[i] = weightMatrix.getData()[tempSource][i];
}//of for i
int[] tempParentArray = new int[numNodes];
Arrays.fill(tempParentArray, tempSource);
// -1 for no parent.
tempParentArray[tempSource] = -1;
//Is it used to mark whether it has already been accessed?
boolean[] tempVisitedArray = new boolean[numNodes];
tempVisitedArray[tempSource] = true;
//Main loops.
//There are n-1 nodes in addition to paraSource. Loop n-1 times the unallocated set is empty.
int tempDistance;
int tempBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
// Step 2.1 Find out the best next node.
tempDistance = MAX_DISTANCE;
for (int j = 0; j < numNodes; j++) {
if (tempVisitedArray[j]) {
// This node is visited.
continue;
}//of if
if (tempDistanceArray[j] < tempDistance) {
tempDistance = tempDistanceArray[j];
tempBestNode = j;
}//of if
}//of for j
resultCost += tempDistanceArray[tempBestNode];
tempVisitedArray[tempBestNode] = true;
//Step 2.2 Prepare for the next round.
for (int j = 0; j < numNodes; j++) {
if (tempVisitedArray[j]) {
// This node is visited.
continue;
}//of if
if (tempDistanceArray[j] > MAX_DISTANCE) {
//can not reach.
continue;
}//of if
if (tempDistanceArray[j] > weightMatrix.getData()[tempBestNode][j]) {
tempDistanceArray[j] = weightMatrix.getData()[tempBestNode][j];
tempParentArray[j] = tempBestNode;
}//of if
//For test
//System.out.println("The selected distance for each node: " + Arrays.toString(tempDistanceArray));
}//of for j
System.out.println(tempBestNode);
}//of for i
return resultCost;
}//of prim
/**
* ****************************************************************
* The entrance of program.
*
* @param args Not used now
* ****************************************************************
*/
public static void main(String args[]) {
Net tempNet0 = new Net(3);
System.out.println(tempNet0);
int[][] tempMatrix1 = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };
Net tempNet1 = new Net(tempMatrix1);
System.out.println(tempNet1);
int[] resultDistanceArray = new int[tempNet1.numNodes];
resultDistanceArray = tempNet1.dijkstra(3);
System.out.println("The distance result of dijkstra is: " + Arrays.toString(resultDistanceArray));
int resultCost;
resultCost = tempNet1.prim(0);
System.out.println("The result cost of the Prim algorithm: " + resultCost);
resultCost = tempNet1.prim();
System.out.println("The result cost of the Prim algorithm: " + resultCost);
}//of main
}//of class Net
(1)自己改prim算法的时候,对比距离的时候把参数整错了。本来该对比当前节点到已经遍历过的节点的距离,找出其中最短距离。结果对比成了当前最优节点的距离,结果运行出错。即将if (tempDistanceArray[j] > weightMatrix.getData()[tempBestNode][j])写成了if (tempDistanceArray[j] > tempDistanceArray[tempBestNode])。
(2)自己改完之后又去看闵老师的代码,发现将起始点设置成了0号节点,于是又改了一个,同时也附上去了。