普鲁姆算法加权最小生成树


一、什么是普鲁姆算法?

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小

二、原理

1、从出发节点开始只能收集出发点和其相临节点的权值,选取收集的权值中最小权值(已被访问节点不在选择范围内),该权值指向节点作为下一个出发点,标记该指向节点已被访问
2、重复步骤1直至所有节点全部被访问

三、代码实现

/**
 * 最小生成树
 * 普里姆算法
 */
public class Test {

	/**
	 * 端点数组
	 */
	private static final String[] ENDPOINT;

	/**
	 * 指向节点的权值数组,下标是尾节点
	 */
	private static final int[] WEIGHT_SIDE;
	/**
	 * 指向某节点最短路径数组,下标尾节点 值为首节点,若值为-1说明该尾节点已经被访问过
	 */
	private static final int[] SHORT_PATH_ENDPOINT;
	/**
	 * 边二维数组
	 */
	private static final Integer[][] SIDE_ARRAY;
	/**
	 * 判断顶点是否被访问过
	 */
	private static final Integer SIDE_FLAG = -1;


	static {
		ENDPOINT = new String[]{"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8"};
		WEIGHT_SIDE = new int[ENDPOINT.length];
		SHORT_PATH_ENDPOINT = new int[ENDPOINT.length];
		for (int i = 0; i < WEIGHT_SIDE.length; i++) {
		    // 因为节点有为0的因此初始化数组是用Integer.MAX_VALUE
			WEIGHT_SIDE[i] = Integer.MAX_VALUE;
			SHORT_PATH_ENDPOINT[i] = Integer.MAX_VALUE;
		}
		SIDE_ARRAY = new Integer[ENDPOINT.length][ENDPOINT.length];
		for (int i = 0; i < ENDPOINT.length; i++) {
			for (int j = 0; j < ENDPOINT.length; j++) {
				SIDE_ARRAY[i][j] = Integer.MAX_VALUE;
			}
		}

		SIDE_ARRAY[0][0] = 0;
		SIDE_ARRAY[1][1] = 0;
		SIDE_ARRAY[2][2] = 0;
		SIDE_ARRAY[3][3] = 0;
		SIDE_ARRAY[4][4] = 0;
		SIDE_ARRAY[5][5] = 0;
		SIDE_ARRAY[6][6] = 0;
		SIDE_ARRAY[7][7] = 0;
		SIDE_ARRAY[8][8] = 0;


		SIDE_ARRAY[0][1] = 10;
		SIDE_ARRAY[1][0] = 10;

		SIDE_ARRAY[0][5] = 11;
		SIDE_ARRAY[5][0] = 11;

		SIDE_ARRAY[1][2] = 18;
		SIDE_ARRAY[2][1] = 18;

		SIDE_ARRAY[1][8] = 12;
		SIDE_ARRAY[8][1] = 12;

		SIDE_ARRAY[1][6] = 16;
		SIDE_ARRAY[6][1] = 16;

		SIDE_ARRAY[2][8] = 8;
		SIDE_ARRAY[8][2] = 8;

		SIDE_ARRAY[2][3] = 22;
		SIDE_ARRAY[3][2] = 22;

		SIDE_ARRAY[3][8] = 21;
		SIDE_ARRAY[8][3] = 21;

		SIDE_ARRAY[3][6] = 24;
		SIDE_ARRAY[6][3] = 24;

		SIDE_ARRAY[3][7] = 16;
		SIDE_ARRAY[7][3] = 16;

		SIDE_ARRAY[3][4] = 20;
		SIDE_ARRAY[4][3] = 20;

		SIDE_ARRAY[4][7] = 7;
		SIDE_ARRAY[7][4] = 7;

		SIDE_ARRAY[4][5] = 26;
		SIDE_ARRAY[5][4] = 26;

		SIDE_ARRAY[5][6] = 17;
		SIDE_ARRAY[6][5] = 17;

		SIDE_ARRAY[6][7] = 19;
		SIDE_ARRAY[7][6] = 19;
	}


	public static void main(String[] args) {
		//随机选择起点、终点
		Random random = new Random();
		int startEndPoint = random.nextInt(ENDPOINT.length - 1);
		String vertex = ENDPOINT[startEndPoint];
		System.out.println("开始最小生成树!开始顶点:" + vertex);
		SHORT_PATH_ENDPOINT[startEndPoint] = -1;
		weightedShortestPath(startEndPoint);
	}


	/**
	 * 获取普里姆算法加权最小生成树
	 * 时间复杂度n的平方
	 *
	 * @param index
	 */
	private static void weightedShortestPath(int index) {

		for (int i = 0; i < ENDPOINT.length; i++) {
			int minWeight = Integer.MAX_VALUE;
			int minEndpoint = -1;
			// 1、遍历当前节点的邻节点 取最小权值 指向的节点下标
			for (int j = 0; j < ENDPOINT.length; j++) {
				int weight = SIDE_ARRAY[index][j];
				// weight == Integer.MAX_VALUE 表示 俩顶点无边 ;index == j表示矩阵对角线 ;SHORT_PATH_ENDPOINT == SIDE_FLAG表示j端点已经被访问过
				if (weight == Integer.MAX_VALUE || index == j || SHORT_PATH_ENDPOINT[j] == SIDE_FLAG) {
					continue;
				}
				// 获取 当前index节点的邻节点最小权值路径
				if (weight < minWeight) {
					minWeight = weight;
					minEndpoint = j;
				}
				if (weight < WEIGHT_SIDE[j]) {
					WEIGHT_SIDE[j] = weight;
					SHORT_PATH_ENDPOINT[j] = index;
				}
			}
			// 将1步骤获取的最小权值指向下标,和之前剩余可用权值比较谁最小,取最小权值下标
			for (int k = 0; k < WEIGHT_SIDE.length; k++) {
				// SHORT_PATH_ENDPOINT[k] == Integer.MAX_VALUE 表示 无最短路径;SHORT_PATH_ENDPOINT[k] == SIDE_FLAG表示端点k已经被访问过
				if (SHORT_PATH_ENDPOINT[k] == Integer.MAX_VALUE || SHORT_PATH_ENDPOINT[k] == SIDE_FLAG) {
					continue;
				}
				int weight = WEIGHT_SIDE[k];
				// minEndpoint == -1说明index节点周围没有未访问过的节点
				if (minEndpoint == -1) {
					minEndpoint = k;
				}
				if (weight < WEIGHT_SIDE[minEndpoint]) {
					minEndpoint = k;
				}
			}
			// 说明已经遍历完成
			if (minEndpoint == -1) {
				continue;
			}
			System.out.println("路径:" + SHORT_PATH_ENDPOINT[minEndpoint] + "-" + minEndpoint + ",权值:" + WEIGHT_SIDE[minEndpoint]);
			// 标记最小权值指向节点已被访问
			SHORT_PATH_ENDPOINT[minEndpoint] = SIDE_FLAG;
			// 将最小权值指向节点作为下一步出发点
			index = minEndpoint;

		}
	}

}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了普鲁姆算法的原理及代码实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值