日撸代码300行:第38天(Dijkstra 算法与 Prim 算法)

代码来自闵老师”日撸 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号节点,于是又改了一个,同时也附上去了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值