图的最小生成树算法-Kruscal算法-并查集-然而未采用堆排序技巧-效率依然低

本文介绍了一段C++代码,用于实现克鲁斯卡尔算法(Kruskal's Algorithm)来找到加权无向图的最小生成树。代码首先初始化图,然后通过插入顶点和设置边权重构建图。接着,使用排序和并查集策略来逐步选择最小权值的边,形成最小生成树。该算法遵循每次连接不在同一集合的顶点的原则,直至连接所有顶点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


#include <iostream>
using namespace std;

#define max_vertex_num 20

int vex_num;//顶点个数
char v[max_vertex_num];//存储顶点
int arcs[max_vertex_num][max_vertex_num];//存储权值

void Initialization();//图的初始化
int LocateVex(char u);//定位顶点u,返回顶点在一维数组v中的下标
void InsertVex(char s);//插入顶点
void SetWeight(int u,int v,int w);//设置权值
void SetWeight(char u,char v,int w);//设置权值

void Kruskal();//算法

int find(int x,int set[],int vex_num)
{//初始时,每个顶点的类标号就是本身的标号 
	int y;
	y=x;
	while(1)
	{//找到x所在集合的根节点 
		if(set[y]==y)
		{//若顶点的类标号是本身,则其是树根 
			break;
		}
		else
		{
			y=set[y];
		}
	}
	
	//从x开始向根,将路径上的结点的双亲直接设置为y
	int r;
	while(1)
	{
		if(set[x]==y)
			break;
		r=set[x];
		set[x]=y;
		x=r;
	}
	return y;
	 
	
}

void merge(int x,int y,int set[],int vex_num)
{//x、y是两个集合的树根。现在要合并在一起
	set[x]=y;
} 

int main(int argc, char* argv[])
{
	Initialization();//图的初始化
	//下面通过插入顶点和插入边,构造图
	InsertVex('a');InsertVex('b');InsertVex('c');
	InsertVex('d');InsertVex('e');InsertVex('f');
	SetWeight('a','b',6);
	SetWeight('a','c',1);
	SetWeight('a','d',5);
	SetWeight('b','c',5);
	SetWeight('b','e',3);
	SetWeight('c','d',5);
	SetWeight('c','e',6);
	SetWeight('c','f',4);
	SetWeight('d','f',2);
	SetWeight('e','f',6);

	//调用Prim算法,生成最小生成树
	Kruskal();

	return 0;
}
void Initialization()
{//图的初始化
	vex_num=0;//开始时,顶点个数为0
	for(int i=1;i<max_vertex_num;i++)
		for(int j=i;j<max_vertex_num;j++)
			arcs[i][j]=arcs[j][i]=99999;//表示无穷大
}

void InsertVex(char s)
{//插入一个顶点
	vex_num++;
	v[vex_num]=s;//vex_num同时代表最后一个顶点在数组v中的下标
}
//
int LocateVex(char u)
{//定位顶点u对应的下标
	for(int i=1;i<=vex_num;i++)
	{	   if(v[i]==u)  return i;   }
	return 0;
}
void SetWeight(int u, int v, int w)
{//设置边上的权值
	arcs[u][v]=arcs[v][u]=w;
}
void SetWeight(char u, char v, int w)
{//设置边上的权值
	SetWeight(LocateVex(u),LocateVex(v),w);
}
void Kruskal()
{
	struct edge
	{ 
		int u;
		int v;
		int length;
	};
    edge L[max_vertex_num];//数组L,用来存储各条边
	
	int index=0;
	int i,j;
	for(i=1;i<=vex_num;i++)
	{
		for(j=i;j<=vex_num;j++)
		{
			if(arcs[i][j]!=99999)
			{
				index++;
				L[index].u=i;
				L[index].v=j;
				L[index].length=arcs[i][j];

			}
		}
	}
	//下面要对L中的边按照length从小到大排序
	//简单选择排序
	for(i=1;i<index;i++)
	{
		for(j=i+1;j<=index;j++)
		{
			if(L[j].length<L[i].length)
			{
				edge t;
				t=L[j];
				L[j]=L[i];
				L[i]=t;
			}
		}
	}

	//输出排好序的边,测试排序程序
	//for(i=1;i<=index;i++)
	//	cout<<L[i].u<<"-->"<<L[i].v<<"   "<<L[i].length<<endl;
	//
	int set[max_vertex_num];
	//初始时,每个顶点自成一个集合
	for(i=1;i<=vex_num;i++)
		set[i]=i;

	int edge_nums=0;//选出到最小生成树中的边的条数
	i=1;//从边集合的第一条边开始取

	while(edge_nums<vex_num-1)
	{
		int x,y;
		//优先选取权值最小的边
		x=find(L[i].u,set,vex_num);//寻找顶点u的类别 
		y=find(L[i].v,set,vex_num);//寻找顶点v的类别 

		if(x!=y)
		{//如果边的两个顶点还不属于同一个集合,则让他们同属一个集合
			cout<<"("<<v[x]<<" , "<<v[y]<<")"<<endl;
			edge_nums++;
			
			//合并顶点x和y的类别 			
			merge(x,y,set,vex_num);			
		}
		i++;

	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值