最小生成树Kruskal算法

本文详细介绍了Kruskal算法,一种用于求解图的最小生成树的问题。内容包括算法的基本思想、快速排序、并查集的原理,以及如何结合这些工具实现Kruskal算法。此外,还提供了C++代码示例,帮助读者理解算法的实现过程。

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

杨乐 2008283046

水一波基础算法。。。。

最小生成树Kruskal算法

该算法涉及到了快速排序算法、并查集,通过快速排序,选择最短边,并查集筛选未相连的边,然后进行边的链接。

快速排序

快速排序算法通过多次比较和交换实现排序,大致流程如下:

  1. 定义一个tmp作为基准数,通过该数把数组分成:比其大和比其小的左右两部分,该值的设定可以为随机值、最左边、最右边和中间,设情况而定。
  2. 将大于或等于基准数的数swap到数组右边,小于基准数的数swap到数组的左边。
  3. 则使用递归方法,左边和右边的数据可以独立排序,每次递归都可设置新的tmp基准数,当左、右两个部分各数排序完成后,整个数组的排序也就完成了。

并查集

并查集是一种数据结构,用于处理一些不相交集合的合并及查询问题,主要操作为初始化、查找和合并。

初始化操作,每个人都是自己圈子里的,即 fat[a] = a;

合并操作,假如a是b的圈子里的,则记为 fat[b] = a;

查询操作,查询a是不是b圈子里的,return x!=fat[x]?find(fat[x]) : x;

所需的时间复杂度很低。

Kruskal算法实现

Kruskal算法是基于贪心的思想得到的。首先我们把所有的边Edge按照边长先从小到大排列,接着按照顺序选取每条边,如果这条边和另一条边相连后,不会形成一个闭环,那么就将它们合并,直到选择的边数等于端点数减一。至于怎么选择边,那么这里我们就可以用到一个工具——-并查集。换而言之,Kruskal算法就是基于并查集的贪心算法。

/**************************
*         2008283046      
*            杨乐          
***************************/
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
using namespace std;
#define N 105

struct Edge{
	int u, v;
	int value;
}e[N];
int fat[N]; // 关系数组 
int sum;
int n, m;
void swp(int &x, int &y){
	int tmp = x;x = y;y = tmp; // swap交换两个数 
}
void quickSort(Edge a[], int left, int right){
	if(left >= right) return; 
	// 分支界限,当left大于right时返回 
	int i = left;
	int j = right;
	int tmp = a[i].value; // 取最左边数当基准数
	while(i != j){
		while(tmp <= a[j].value && i < j) j --;
		// 从右边查看第一个小于tmp的值 
		while(tmp >= a[i].value && i < j) i ++;
		// 从左边查看第一个大于tmp的值 
		if(i != j) swap(a[i], a[j]);
		// 交换找到的值 
	}
	swap(a[left], a[i]);
	// 基准数归位 
	quickSort(a, left, i - 1); // 分治法处理左边 
	quickSort(a, i + 1, right);// 分治法处理右边 
}

int find(int x){
	while(x!=fat[x]){ //找到自身停止
		x=fat[x];
	}
	return x;
}
bool islink(int x,int y){
	int i = find(x);
	int j = find(y);
	if(i != j){ //查看两者是否有关联
		fat[i] = j; //无关联就将其关联起来
		return true;
	}
	else return false;
}
void input(){
	freopen("data.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	cout << "请依次输入点和边的数量以及边: " << endl;
	cin >> n >> m;
	for(int i = 0; i < n; i++){
		fat[i] = i;
	}
	for(int i = 0;i < m; i++){
		cin >> e[i].u >> e[i].v >> e[i].value;
	}
	quickSort(e, 0, m - 1);
}
int main(){
	int count = 0;
	sum = 0;
	input();
	for(int i = 0; i < m; i++){
		if(islink(e[i].u, e[i].v)){ // 通过并查集的关系选边
			sum += e[i].value;
			printf("连接 %d, %d.\n", e[i].u, e[i].v, e[i].value);
			count ++;
		}
		if(count == m - 1) break;
	}
	cout << "最小生成树的长度是: " << sum << endl;
	return 0;
}
/*
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值