推免复习之数据结构与算法 Kruskal算法(最小生成树)

本文纠正了之前关于克鲁斯卡尔算法的错误理解,详细介绍了使用三元组数据结构和快速排序进行最小生成树构建的过程。通过实例演示了如何避免回环,确保生成的树是最小生成树。

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

非常尴尬,我之前写的那篇写克鲁斯卡尔算法的那篇博客思路是错误的,我当时也不知道是被哪篇博客误导了,汗。

所以我在这里重新写一篇正确的,而且事先声明,我没有使用并查集,我只是使用了一个label数组来记录各个顶点各属于哪个集合,其他与正常求克鲁斯卡尔算法的思路一致。

首先是使用三元组数据表作为存储的数据结构,每条边的数据结构如下所示:

class edge
{
public:
	int start;
	int end;
	int weight;
	edge(int s,int e,int w)
	{
		start = s;
		end = e;
		weight = w;
	}
};

然后使用stl中的快排对权值进行升序排序 ,对排完序的三元表数组就可以进行克鲁斯卡尔算法了。对这个数组进行从头到尾遍历,如果两个顶点分别属于不同集合,则添加此边,否则不添加,以避免最小生成树中形成回环。直到遍历完所有边,如果该图是连通图,则生成的一定是最小生成树。

全部的代码如下所示,我添加了注释的部分是对顶点做标记的代码,很重要!

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

class edge
{
public:
	int start;
	int end;
	int weight;
	edge(int s,int e,int w)
	{
		start = s;
		end = e;
		weight = w;
	}
};

bool compare(edge a,edge b)
{
	return a.weight < b.weight;
}

void InputGraph(vector<edge> &graph)
{
	int n = 0;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int start = -1, end = -1, weight = 0;
		cin >> start >> end >> weight;
		graph.push_back(edge(start,end,weight));
	}
	sort(graph.begin(),graph.end(),compare);
}


int kruskal(vector<edge> &graph)
{
	int size = graph.size();
	int weight = 0;
	vector<int> label(size);
	for (int i = 0; i < size; i++)  //为每个顶点设置标签,以避免回环
	{
		label[i] = i;
	}
	cout << endl;
	for (int i = 0; i < size; i++)
	{
		if (label[graph[i].start]!=label[graph[i].end])
		{
			int flag = label[graph[i].start];
			int toChange = label[graph[i].end];
			for (int j = 0; j < size; j++)   //把所连接的左连通分支每个顶点都打上右连通分支的记号
			{
				if (label[j] == flag)
				{
					label[j] = toChange;
				}
			}
			weight += graph[i].weight;
			cout << graph[i].weight << endl;
		}
	}
	return weight;
}

int main()
{
	vector<edge> graph;
	InputGraph(graph);
	cout << kruskal(graph) << endl;
	system("pause");
	return 0;
}

输入:

8

0 1 2

0 2 3

1 3 7

2 3 5

2 4 3

3 4 4

4 5 2

1 5 8

输出的总权值应该是14,和使用prim算法所得的一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值