最小生成树(Prim算法——纯C++)

关于图的几个概念定义:

  • 连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图。
  • 强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向图为强连通图。
  • 连通网:在连通图中,若图的边具有一定的意义,每一条边都对应着一个数,称为权;权代表着连接连个顶点的代价,称这种连通图叫做连通网。
  • 生成树:一个连通图的生成树是指一个连通子图,它含有图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。
  • 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。

在这里插入图片描述
下面我们总结第一种生成最小生成树的算法

一、Prim算法

这个方法的原理就是:
1.将原图划分成“点-边-点”的边集合,并且将所有的点建立离散点集合。并建立生成树的边集合和点集合。
2.找到原图的边集合中权值最小的边当作“种子”,将边加入生成树的边,并在离散点中找到两个端点,删除,加入生成树的点集合。
3.遍历原图的边,找到符合“一端在生成树的点集合,一端在离散的点集合,并且权值最小”的边。将该边不在生成树的一端从离散点集合删除,加入到生成树点集合。将该边加入到生成树的边集合,从原图的边集合删除。

首先

(1)声明边类型,边数组类型,点数组类型

struct 边类型{
	int p0,p1;
	int k;
	边类型(int p0=0, int p1=0, int k=0):p0(p0),p1(p1),k(k){  }
};

struct 图的边类型{
	边类型 *边数组;
	const int Size;
	int n;
	图的边类型(int Size):Size(Size),n(0){ 边数组 = new 边类型[Size]; }
	~图的边类型( ){ delete [ ]边数组; }
	int MinNdx( ){
		int minX=0;
		for(int i=0; i<n; i++){
			if(边数组[i].k < 边数组[minX].k)
				minX = i;
		}
		return minX;
	}
	边类型 Delete(int Ndx){
		边类型 边 = 边数组[Ndx];
		for(int i=Ndx+1; i<n; i++){
			边数组[i-1] = 边数组[i];
		}
		n = n-1;
		return;
	}
	void Append(边类型 边){
		边数组[n] =;
		n++;
	}
};
struct 图的点类型{
	const int Size;
	int *点数组;
	int n;
	图的点类型(int Size):Size(Size),n(0){ 点数组 = new int[Size]; }
	~图的点类型( ){ delete [ ]点数组; }
	int Delete(int Ndx)// 删除下标为Ndx的点(int),并且把删除的点(int)return 回去
	{
		int= 点数组[Ndx];
		for (int i=Ndx + 1;i < n;i++) {
			点数组[i - 1] = 点数组[i];
		}
		n = n - 1;
		return;
	}
	void Append(int) {
		点数组[n] =;
		n++;
	}
	bool IN(int, int &Ndx){
		for(int i=0; i<n; i++){
			if (== 点数组[i]) {
				Ndx = i;
				return true;
			}
		}
		return false;
	}
};

(2)具体操作同上,在程序中也做了注释

int _tmain(int argc, _TCHAR* argv[])
{
	图的点类型 生成树的点(6), 离散的点(6);
	图的边类型 原图的边(10),生成树的边(10);
	for(int i=1; i<=6; i++)
		离散的点.Append(i);

	原图的边.Append(边类型(1,2,6)); 原图的边.Append(边类型(1,3,1)); 原图的边.Append(边类型(1,4,5));
	原图的边.Append(边类型(2,3,5)); 原图的边.Append(边类型(3,4,5)); 原图的边.Append(边类型(2,5,3));
	原图的边.Append(边类型(3,5,6)); 原图的边.Append(边类型(3,6,4)); 原图的边.Append(边类型(4,6,2));
	原图的边.Append(边类型(5,6,6));

	边类型 边(0,0,0);
	//1、找到权值最小的边,把它的两个端点加入到生成树的点
	//	(1)、在原图边的集里找到权值最小的边A,从原图的边里面把它删出来= 原图的边.Delete(原图的边.MinNdx( ));
	//	(2)、在离散的点里找到A的两个端点,把它们删出来,加到生成树的点里
	int X_Ndx,Y_Ndx;
	离散的点.IN(.p0, X_Ndx);
	离散的点.Delete(X_Ndx);  
	生成树的点.Append(.p0);
	离散的点.IN(.p1, Y_Ndx);	离散的点.Delete(Y_Ndx);    生成树的点.Append(.p1);
	//	(3)、把A添加到生成树的边
	生成树的边.Append();

	//2、
	while(离散的点.n > 0){
		int NdxTemp;
		int MinNdx = -1;
		for(int i=0; i<原图的边.n; i++){
			//if(原图的边.边数组[i],一端在生成树的点里,另一端在离散的点里){= 原图的边.边数组[i];
			if(生成树的点.IN(.p0,NdxTemp)!=生成树的点.IN(.p1,NdxTemp)){
				if(MinNdx == -1) MinNdx = i;

				if(原图的边.边数组[i].k < 原图的边.边数组[MinNdx].k) MinNdx = i;
			}
		}
		//把原图的边.边数组[MinNdx]的不在生成树上的端点移动到生成树上(即从离散的点里删出来,追加到生成树的点)= 原图的边.边数组[MinNdx];
		if (生成树的点.IN(.p0, NdxTemp)) 
		{ 
			生成树的点.Append(.p1); 
			离散的点.Delete(.p1); 
		}
		else {
			生成树的点.Append(.p0);
			离散的点.Delete(.p0);
		}

		//把下标MinNdx的边从原图的边删出来,追加到生成树的边里
		原图的边.Delete(MinNdx); 生成树的边.Append();
	}

	return 0;
}

这个方法主要是以一个最小权值边最为种子,接着找对于种子来说** “可以连通的,并且权值最小的边” **进行连通。
希望对你们算法理解有所帮助!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值