day38

Day38 —— Dijkstra and Prim

1. Background

今天学习的是,Dijkstra算法和prim算法,这两个算法是数据结构里面最经典的算法。

Dijkstra算法是求一个图中一个点到其他所有点的最短路径的算法。

Prim算法是查找连通网中的最小生成树。

2. Description

2.1 Dijkstra

Dijkstra 算法是一个基于「贪心」、「广度优先搜索」、「动态规划」求一个图中一个点到其他所有点的最短路径的算法,时间复杂度 O(n2)。

每次从 「未求出最短路径的点」中 取出 距离距离起点 最小路径的点,以这个点为桥梁 刷新「未求出最短路径的点」的距离

我们以老师的测试数据为例
t e m p M a t r i x 1 = [ 0 9 3 6 5 0 2 4 3 2 0 1 2 8 7 0 ] tempMatrix1 = \begin{bmatrix} 0 & 9 & 3 & 6 \\ 5 & 0 & 2 & 4 \\ 3 & 2 & 0 & 1 \\ 2 & 8 & 7 & 0 \\ \end{bmatrix} tempMatrix1=0532902832076410
在这里插入图片描述

如果是从0节点开始,那么把tempVisitedArray[0]改为true,再找到它所有的出度所链接的节点。图中可以看到,有1,2,3。然后在其中找权值最小的一条线,也就是比较tempDistanceArrayde 值,并储存。在寻找期间需要不断的回溯,确保最后的结果是最短路径。后面的步骤就是重复之前的操作。

0 ----> 2 : 3

0 ----> 2 ---->3 : 3 + 1 = 4

0 ----> 2 ----> 1 : 3 + 2= 5

2.2 Prim

普里姆算法的实现思路就比较简单直接了:

  1. 将连通网中的所有顶点分为两类(假设为 A 类和 B 类)。初始状态下,所有顶点位于 B 类;
  2. 选择一个最佳的顶点,将其从 B 类移动到 A 类;
  3. 从 B 类的所有顶点出发,找出一条连接着 A 类中的某个顶点且权值最小的边,将此边连接着的 A 类中的顶点移动到 B 类;
  4. 重复执行第 3 步,直至 B 类中的所有顶点全部移动到 A 类,恰好可以找到 N-1 条边。

t e m p M a t r i x 1 = [ 0 7 10000 5 10000 7 0 8 9 7 10000 8 0 10000 5 5 9 10000 0 15 10000 7 5 15 0 ] tempMatrix1 = \begin{bmatrix} 0 & 7 & 10000 & 5 & 10000 \\ 7 & 0 & 8 & 9 & 7 \\ 10000 & 8 & 0 & 10000 & 5 \\ 5 & 9 & 10000 & 0 & 15 \\ 10000 & 7 & 5 & 15 & 0 \\ \end{bmatrix} tempMatrix1=071000051000070897100008010000559100000151000075150

在这里插入图片描述

首先找到这个最佳的节点,这里是0号节点。

然后将它看作B类,再找到权值最小的那个边,这里找的是0到3的这条边,然后顺着这条边,把3也连带着看作B类。将其看作一个整体。后面的以此类推就行。

3. Code

package datastructure.graph;

import java.util.Arrays;
import matrix.IntMatrix;

public class Net {
    // 距离的最大值
	public static final int MAX_DISTANCE = 10000;

	// 节点数。
	int numNodes;

	// 权值矩阵。
	IntMatrix weightMatrix;

	/**
	 *********************
	 * The first constructor.
	 * 
	 * @param paraNumNodes The number of nodes in the graph.
	 *********************
	 */
	public Net(int paraNumNodes) {
		numNodes = paraNumNodes;
		weightMatrix = new IntMatrix(numNodes, numNodes);
		for (int i = 0; i < numNodes; i++) {
			Arrays.fill(weightMatrix.getData()[i], MAX_DISTANCE);
		} // Of for i
	}// Of the first constructor

	/**
	 *********************
	 * The second constructor.
	 * 
	 * @param paraMatrix The data matrix.
	 *********************
	 */
	public Net(int[][] paraMatrix) {
		weightMatrix = new IntMatrix(paraMatrix);
		numNodes = weightMatrix.getRows();
	}// Of the second constructor

	// 一个简单的toString方法。
	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) {
		// Step 1. Initialize.
		int[] tempDistanceArray = new int[numNodes];
		for (int i = 0; i < numNodes; i++) {
			tempDistanceArray[i] = weightMatrix.getValue(paraSource, i);
		} // Of for i

		int[] tempParentArray = new int[numNodes];
		Arrays.fill(tempParentArray, paraSource);
		// -1 for no parent.
		tempParentArray[paraSource] = -1;

		// 略过已处理过的节点。
		boolean[] tempVisitedArray = new boolean[numNodes];
		tempVisitedArray[paraSource] = true;

		// Step 2. 迪杰斯特拉算法的主要内容。
		int tempMinDistance;
		int tempBestNode = -1;
		for (int i = 0; i < numNodes - 1; i++) {
			tempMinDistance = Integer.MAX_VALUE;
			for (int j = 0; j < numNodes; j++) {
				if (tempVisitedArray[j]) {
					continue;
				} // Of if

				if (tempMinDistance > tempDistanceArray[j]) {
					tempMinDistance = tempDistanceArray[j];
					tempBestNode = j;
				} // Of if
			} // Of for j

			tempVisitedArray[tempBestNode] = true;

			// 为下一轮做准备。
			for (int j = 0; j < numNodes; j++) {
				if (tempVisitedArray[j]) {
					continue;
				} // Of if

				if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {
					continue;
				} // Of if

				if (tempDistanceArray[j] > tempDistanceArray[tempBestNode] + weightMatrix.getValue(tempBestNode, j)) {
					tempDistanceArray[j] = tempDistanceArray[tempBestNode] + weightMatrix.getValue(tempBestNode, j);
					tempParentArray[j] = tempBestNode;
				} // Of if
			} // Of for j

			// For test
			System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));
			System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
		} // Of for i

		// Step 3. 输出。
		System.out.println("Finally");
		System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));
		System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
		return tempDistanceArray;
	}// Of dijkstra

	/**
	 *********************
	 * The minimal spanning tree.
	 * 
	 * @return The total cost of the tree.
	 *********************
	 */
	public int prim() {
		int tempSource = 0;
		int[] tempDistanceArray = new int[numNodes];
		for (int i = 0; i < numNodes; i++) {
			tempDistanceArray[i] = weightMatrix.getValue(tempSource, i);
		} // Of for i

		int[] tempParentArray = new int[numNodes];
		Arrays.fill(tempParentArray, tempSource);
		tempParentArray[tempSource] = -1;

		// 略过已访问的节点
		boolean[] tempVisitedArray = new boolean[numNodes];
		tempVisitedArray[tempSource] = true;

		// prim算法的主要内容。
		int tempMinDistance;
		int tempBestNode = -1;
		for (int i = 0; i < numNodes - 1; i++) {
			// 找到那个最佳的节点
			tempMinDistance = Integer.MAX_VALUE;
			for (int j = 0; j < numNodes; j++) {
				if (tempVisitedArray[j]) {
					continue;
				} // Of if

				if (tempMinDistance > tempDistanceArray[j]) {
					tempMinDistance = tempDistanceArray[j];
					tempBestNode = j;
				} // Of if
			} // Of for j

			tempVisitedArray[tempBestNode] = true;

			// 为下一轮做准备。
			for (int j = 0; j < numNodes; j++) {
				if (tempVisitedArray[j]) {
					continue;
				} // Of if

				// 无法找到的节点
				if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {
					continue;
				} // Of if

				if (tempDistanceArray[j] > weightMatrix.getValue(tempBestNode, j)) {
					// Change the distance.
					tempDistanceArray[j] = weightMatrix.getValue(tempBestNode, j);
					// Change the parent.
					tempParentArray[j] = tempBestNode;
				} // Of if
			} // Of for j

			// For test
			System.out.println("The selected distance for each node: " + Arrays.toString(tempDistanceArray));
			System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
		} // Of for i

		int resultCost = 0;
		for (int i = 0; i < numNodes; i++) {
			resultCost += tempDistanceArray[i];
		} // Of for i

		// 输出。
		System.out.println("Finally");
		System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
		System.out.println("The total cost: " + resultCost);

		return resultCost;
	}// Of prim

	/**
	 *********************
	 * The entrance of the 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);

		tempNet1.dijkstra(1);
        System.out.println();

		// 建立一个无向网。
		int[][] tempMatrix2 = { { 0, 7, MAX_DISTANCE, 5, MAX_DISTANCE }, { 7, 0, 8, 9, 7 },
				{ MAX_DISTANCE, 8, 0, MAX_DISTANCE, 5 }, { 5, 9, MAX_DISTANCE, 0, 15 },
				{ MAX_DISTANCE, 7, 5, 15, 0 } };
		Net tempNet2 = new Net(tempMatrix2);
		tempNet2.prim();
	}// Of main
}

运行结果:

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值