最小生成树(Prim算法和Kruskal算法)

什么是最小生成树?

生成树的代价: 设G=(V,E)是一个无向连通网,生成树上各边的权值之和叫做该生成树的代价。
最小生成树: 图G的所有生成树中,代价最小的生成树,叫做最小生成树。

构造最小生成树的算法

1.Prim算法(加点法)
2.Kruskal算法(加边法)

1.Prim算法

基本思想:
1、创建一个顶点集合U,和一个边集合TE。
2、若从u开始,则将u放入U中,V总顶点集合则少一个u,
3、在u∈U,v∈V-U的两个顶点集合里找出代价最小的边(u,v),加入边集TE,同时把v加入U中。重复操作。

数据结构设计

设数组adjvex[n]表示候选最短边的领接点

设数组lowcast[n]表示权值

其值如下,含义是候选最短边(i,j)的权值为w,其中i∈V-U , j∈U

adjvex[i] = j

lowcost[i] = w

伪代码
1.初始化两个辅助数组lowcostadjvex
2.输出顶点u,将定点u加入集合U中。
3.重复执行以下操作n-1次:
3.1在lowcost中选取最短的边(lowcost[k]),获取对应的顶点序号k。
3.2输出顶点k和对应的权值。
3.3将顶点k加入集合U中;
3.4调整数组的lowcost和adjvex

上代码

void Prim(Graph G){
	for(int i=0;i<G.vertexNum;i++){
		lowcost[i]=G.arc[0][i];adjvex[i]=0;	//初始化辅助数组,从第一个节点(下标为0的点)开始
	}
	lowcost[0]=0;	//第一个顶点放入集合U中
	for(int i=1;i<G.vertexNum;i++){		//循环n-1次
		k=MinEdge(lowcost,G.vertextNum);	//找出权值最小的边,返回边(0,k)的终点k
		cout<<k<<adjvex[k]<<lowcost[k];		//输出k,k的最短边邻接点,最短边的权值
		lowcost[k]=0;		//k放入集合U
		for(int j=1;j<G.vertexNum;j++){		//修改lowcost和adjvex的数据
			if(G.arc[k][j]<lowcost[j]){		//遍历所有点与k邻接的点所成的边,若arc[k][j]比之前的lowcost更小,必须更新数据。
				lowcost[j]=G.arc[k][j];//最小边的权值修改
				adjvex[j]=k;		//最短边的邻接点也许修改,j的修改成k。(原来是初始点0,需更新成k。)
			}
		}
	}
}


//下面是求出最小边的邻接点终点k的函数
int MinEdge(int  *lowcost, int num) {
  int min = 100000;		//写一个较大的数
  int index = -1;		//初始化下标
  for(int i = 0; i < num; i++) {			//n次循环找出最小
    if(lowcost[i] < min && lowcost[i] != 0) {
      min = lowcost[i];			//最小权值找到
      index = i;			//最小边的邻接终点,循环结束后返回出去
    }
  }
  return index;
}


2.Kruskal算法

基本思想:
1.将图中所有的边按权值大小排序。
2.从最小的边开始选,所选边与已选边处于不同连通分量则可,处于同一个连通分量就舍弃该边,继续选后面的,以免构成回路。
3.重复下去,若最后连通分量为1,则构造完成最小生成树

伪代码
1.初始化:U=V,TE={ };
2.循环直到连通分量为1
2.1在E中寻找最短边(u,v);
2.2若两边位于不同连通分量,则
2.2.1将边(u,v)并入TE;并且将两个连通分量合为一个;
2.3 标记(u,v),防止之后再被选取;

Kruskal算法实现中的三个关键问题

1.图的存储结构是边集数组

2.如何判断两个边在不同的连通分量上?
用到并查集,定义parent[i]数组,数组的值表示双亲节点(初始值为-1);
当一条边的两个顶点的根节点不同时,这两个点属于不同的连通分量
(利用parent数组查找树的根节点,当一个节点n的parent为-1时,根节点就是n)

3.连通分量的合并?
一个分量的根节点使v1,另一个使v2,使parent[v2]=v1;实现连通.

发布了36 篇原创文章 · 获赞 3 · 访问量 3531

猜你喜欢

转载自blog.csdn.net/qq_43628835/article/details/103338270
今日推荐