普利姆(Prim)算法Java语言描述

普利姆算法

构造连通网的最小代价生成树称为最小生成树。
我们通过构造一个图来说明这个算法。
在这里插入图片描述
对这个图写出其arc邻接矩阵:
在这里插入图片描述
在之前的图的存储就够中,已经有了一个存储结构为MGragh的邻接矩阵,其中,INFINITY代表∞,我们用数字65535来表示。现在,我们来看其核心代码:

public void MinSpanTree(){
	int min,j,k;
	int[] adjvex = new int[this.vertexs];//记录顶点下标的数组
	int[] lowcost = new int[this.vertexs];//记录顶点间边的权值
	adjver[0] = 0;//初始化,将第一个置为0
	lowcost[0] = 0;//第一个值为0,说明第一个顶点A0已经加入了生成树
	for(int i=1;i<this.vertexs;i++){
		lowcost[i] = this.arc[0][i];//将与A0相连的顶点间的权值全部加入到此数组
		//即,将arc矩阵的第一行加入到此数组
		adjvex[i] = 0;//全部置为零
	}
	//到此,算法的准备工作全部做完
	System.out.println("图的最小生成树为:");
	for(int i=1;i<this.vertexs;i++){//第一个for循环
		min = INFINITY;//初始化,将65535赋予min
		j = 1;
		k = 0;
		while(j<this.vertexs){//循环全部的顶点
			//判断此顶点是否访问过并且该顶点是否小于min值
			if(lowcost[j]!=0&&lowcost[j]<min){
				min = lowcost[j];//将更小的值赋予min
				k = j;//用k来保存该顶点的下标
			}
			j++:
		}
		//打印当前顶点边中权值最小边,如打印  (0,1) 权值:1
		System.out.println("("+adjvex[k]+","+"k"+")"+" 权值:"+lowcost[k]);
		lowcost[k] = 0;//将访打印过的顶点置为0,表示已被访问过
		for(j=1;j<this.vertexs;j++){//第二个for循环
			//判断顶点是否访问过并且arc矩阵中k行的所有顶点间权值是否小于lowcost数组中原来的值
			if(lowcost[j]!=0&&this.arc[k][j]<lowcost[j]){
				lowcost[j] = this.arc[k][j];//若小于,将该值替换
				adjvex[j] = k;//将访问过的顶点下标k放进adjvex数组
			}
		}
	}
}

通过上述代码,我们将开始的图带入该算法,一步一步进行计算。

开始时:lowcost=[0,1,1,4];adjvex=[0,0,0,0];

1. while循环后: min=1,k=1 打印(0,1),然后lowcost[1] = 0;
2. 第二个for循环后:lowcost=[0,0,1,4],adjvex=[0,0,0,0];
3. while循环后:min=1,k=2 打印(0,2),然后lowcost[2]=0;
4. 第二个for循环后:lowcost=[0,0,0,3],adjvex=[0,0,0,2];
5. while循环后:min=3,k=3 打印(2,3),然后lowcost[3]=0;
6. 第二个for循环后:lowcost=[0,0,0,0],adjvex=[0,0,0,3]
7. 至此,所有顶点全部访问过,lowcost中的数组全为0,最终退出第一个for循环。

我们将图的代码和普利姆算法的全部代码给出:

public class MyGraph{
	public static final int INFINITY = 65535;	//用65535表示∞
	private String[] vertexdata;	//顶点信息数组
	private	int[][] arc;	//邻接矩阵表
	private int w;	//权值
	private int vertexs;	//顶点数
	private int edges;	//边数
	public MyGraph(){
		this.vertexs = 0;
		this.edges = 0;
	}
	//创建并存储一个无向图(邻接矩阵)
	public void CreateMyGraph(){
		Scanner scanner = new Scanner(System.in);
		System.out.print("请输入顶点数和边数:");
		this.vertexs = scanner.nextInt();
		this.edges = scanner.nextInt();
		arc = new int[vertexs][vertexs];
		vertexdata = new String[vertexs];
		visited = new boolean[vertexs];
		edge = new Edges[this.edges];
		for(int i=0;i<vertexs;i++){
			for(int j=0;j<vertexs;j++){
				arc[i][j] = INFINITY;
			}
		}
		for(int i=0;i<this.edges;i++){
			edge[i] = new Edges();
		}
		System.out.print("请输入顶点信息:");
		for(int i=0;i<this.vertexs;i++){
			vertexdata[i] = scanner.next();
		}
		for(int i=0;i<this.edges;i++){
			System.out.print("请输入边(vi,vj)上的下标i,下标j和权w:");
			int v1 = scanner.nextInt();
			int v2 = scanner.nextInt();
			this.w = scanner.nextInt();
			arc[v1][v2] = this.w;
			arc[v2][v1] = arc[v1][v2];
			edge[i].begin = v1;
			edge[i].end = v2;
			edge[i].weight = w;
		}
	}
	//最小生成树--普里姆算法
	/*对图的顶点进行操作“加点法”
	 这种算法需要创建两个数组,adjvex和lowcost,它们分别是存储相关顶点下标和邻接矩阵中某行的权值
	 利用这两个数组,对邻接矩阵进行遍历,然后寻找权值小的顶点,最后将最小权值的顶点打印。其中,
	 lowcost数组中如果数值有0,则说明给顶点已经被“访问”。
	 */
	public void MinSpanTree_Prim(){
		int i,j,min;
		int k;
		int[] adjvex = new int[this.vertexs];//存储相关顶点下标
		int[] lowcost = new int[this.vertexs];//存储邻接矩阵的其中一行
		lowcost[0] = 0;//将第一个顶点v0加入生成树
		adjvex[0] = 0;//初始化第一个顶点下标为0
		for(i=1;i<this.vertexs;i++){//初始化
			lowcost[i] = arc[0][i];//将邻接矩阵的第一行赋予lowcost
			adjvex[i] = 0;//初始化都为v0的下标0
		}
		System.out.println("Prim的最小生成树为:");
		for(i=1;i<this.vertexs;i++){
			min = INFINITY;
			j = 1;
			k = 0;
			//比较出在lowcost中顶点间边的权值的最小值min,然后记录当前最小值的下标k
			while(j<this.vertexs){
				if(lowcost[j]<min&&lowcost[j]!=0){
					min = lowcost[j];
					k = j;
				}
				j++;
			}
			System.out.println("("+adjvex[k]+","+k+")"+" 权值:"+lowcost[k]);
			lowcost[k] = 0;//将已经访问过的顶点置为0
			//因为已经访问过下标为k的顶点,所以继续遍历与下标为k的顶点相连接的顶点
			for(j=1;j<this.vertexs;j++){
				//判断相连接的顶点间的权值是否为0且它们间的权值是否小于此前顶点间的权值
				if(lowcost[j]!=0&&lowcost[j]>arc[k][j]){
					lowcost[j] = arc[k][j];//将更小的权值赋予lowcost中
					adjvex[j] = k;//将下标为k的顶点存入adjvex
				}
			}
			//此轮for循环结束后,进入上层for循环,继续遍历寻找最小的权值,并打印相连接顶点
			//直到所有的顶点遍历完
		}
	}
}

我们进行用例测试:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值