JAVA数据结构--------Prim(普里姆算法)图的遍历和最小生成树

最近复习到了数据结构中图的遍历和最小生成树部分,我在这里记录用java写的prim算法,方便自己回顾,并且与他人交流学习。

算法简介

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小,普里姆算法是基于贪心策略的一种算法,他将按照逐个顶点连通的方式构造最小生成树

算法思想

通过例题来陈述思想,
在这里插入图片描述代码思路:
1.构造 lowcost:最小代价的权值数组,此数组的作用就是找最小的权值
构造 adjvex:存放已经找到最小权值的权重和起点,比如adjvex[1] = 9,表示在最小生成树中有一条起点为v1的权值为9的边。
2.初始化lowcast数组,把起始点到每个顶点权值给他,此题中也就是邻接矩阵的第一行。
3.找邻接矩阵中的最小值,此题中应该是10,是v0->v1的权值,min(最小值)为10,minId(最小值权值的终点)为v1,将lowcast[minid] = 0,意思就是v0到v1已经找到最小权,不在参与lowcast的更新。将adjvex[1] = 10,在最小生成树中有v0->v1权值为10.
4.更新lowcast:将邻接矩阵中的v1那一行和lowcast做比较,取最小值替换掉lowcast中的值。
5.不断重复步骤3和步骤4,顶点有多少个就循环顶点次数减一次,也可以是lowcast中的所有值为都为0

在代码中也有相应的注释,可以配合注释和最后手写的解题步骤更容易理解。

代码实例

/***
 * 使用普里姆算法生成最小生成树
 * @author 65481
 *
 */
public class PrimGraph {
	
	//顶点数量
	private int vertexSize;
	//临接矩阵
	private int [][] matrix;
	//存放顶点的数组
	private int [] vertexs;
	//表示顶点之间没有关系
	private static int MAX_WIGHT = 1000;
	//表示顶点是否被访问过	
	private boolean [] isvisited;
	
	
	//构造函数	 
	public PrimGraph(int vertexSize) {
		this.vertexSize = vertexSize;
		matrix = new int[vertexSize][vertexSize];
		vertexs = new int[vertexSize];
		for(int i = 0;i < vertexSize;i ++) {
			vertexs[i] = i;
		}
		isvisited = new boolean[vertexSize];
	}
	
	
	/**
	 * 普里姆算法
	 */
	public void prim() {
		
		//最小代价顶点权值的数组,0表示已经是最小的了
		int [] lowcost = new int[vertexSize];
		//存放已经比较过后的顶点权值
		int [] adjvex = new int [vertexSize];
		
		//min表示这一行最小的那条边,minId表示最小那条边的下标 ,权值总和
		int min,minId,sum = 0;
		
		//把邻接矩阵的第一行放入到最小代价顶点权值数组
		for(int i = 1;i < vertexSize;i ++) {
			lowcost[i] = matrix[0][i];
		}
		
		//在lowcost中找到最小的权值并且记录权值大小到adjvex对应的位置中,记录最小值min,记录最小那条边的下标minId
		for(int i  = 1;i < vertexSize ;i ++) {
			//初始化
			min  = MAX_WIGHT;
			minId = 0 ;
			for(int j = 1 ;j <vertexSize ; j++) {
				if(lowcost[j] > 0 &&lowcost[j] < min) {
					min = lowcost[j];
					minId = j;
				}
			}
			System.out.println("顶点:"+adjvex[minId]+"权值:"+min);
			sum+=min;
			lowcost[minId] = 0;
			for(int j = 1;j < vertexSize;j ++) {
				//更新lowcost
				if (lowcost[j] !=0 && lowcost[j] > matrix[minId][j]) {
					lowcost[j] = matrix[minId][j];
					adjvex[j] = minId;
				}
			}
		}
		System.out.println("最小生成树权值和为:"+sum);
		
		
	}
	
	
	public static void main(String []args) {
		
		PrimGraph primGraph = new PrimGraph(9);
		
		int [] a0 = new int[]{0,10,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,11,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT};
		int [] a1 = new int[]{10,0,18,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,16,MAX_WIGHT,12};
		int [] a2 = new int[]{MAX_WIGHT,MAX_WIGHT,0,22,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,8};
		int [] a3 = new int[]{MAX_WIGHT,MAX_WIGHT,22,0,20,MAX_WIGHT,MAX_WIGHT,16,21};
		int [] a4 = new int[]{MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,20,0,26,MAX_WIGHT,7,MAX_WIGHT};
		int [] a5 = new int[]{11,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,26,0,17,MAX_WIGHT,MAX_WIGHT};
		int [] a6 = new int[]{MAX_WIGHT,16,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,17,0,19,MAX_WIGHT};
		int [] a7 = new int[]{MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,16,7,MAX_WIGHT,19,0,MAX_WIGHT};
		int [] a8 = new int[]{MAX_WIGHT,12,8,21,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,MAX_WIGHT,0};
			
		
		primGraph.matrix[0] = a0;
		primGraph.matrix[1] = a1;
		primGraph.matrix[2] = a2;
		primGraph.matrix[3] = a3;
		primGraph.matrix[4] = a4;
		primGraph.matrix[5] = a5;
		primGraph.matrix[6] = a6;
		primGraph.matrix[7] = a7;
		primGraph.matrix[8] = a8;
		
		primGraph.prim();
	}

算法结果

顶点:0权值:10
顶点:0权值:11
顶点:1权值:12
顶点:8权值:8
顶点:1权值:16
顶点:6权值:19
顶点:7权值:7
顶点:7权值:16
最小生成树权值和为:99

帮助理解

这里有一些不好理解的地方:
有关于for循环如代码所示,v0和v1有最小的权值为10,下面应该从v1开始,排除v0去找最小的权值。
代码的实现思路是用临接矩阵中的第一行和lowcast数组中的值进行比较,把较小的放入lowcast,然后开始第二次for循环(第二次就相当于从v1开始),动手写一写有助于开导思路(只写了前两次循环):
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43507104/article/details/102484115
今日推荐