算法知识点———并查集

并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。并查集支持两种操作:

合并(Union):合并两个元素所属集合(合并对应的树)

查询(Find):查询某个元素所属集合(查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合。

经典用法:利用并查集检测图中是否有环。

初始parent数组可以设置为下标,表示结点的父亲结点是自己。

然后当结点1和结点2有边的时候可以设置结点2的父亲结点是结点1.结点3的父结点是结点4,那么parent3 = 4

然后如果1和3这条边想合并的时候只需要合并1的父结点和3的父结点即可,也就是1的父结点是4.这样01234都在一个集合里面,也就是说root0 == root2 表示0和2是互通的。

下面是合并x节点和y节点的过程

第一步find_root函数找到x节点的根结点或者y节点的根结点

第二步uniin函数合并x节点和y节点

并查集合并的时候容易导致树倾斜,可以采用秩优化;

每次合并都把深度较小的集合合并在深度较大的集合下面 。这种技术被称为按秩合并
路径压缩 实际上是在找完根结点之后,在递归回来的时候顺便把路径上元素的父亲指针都指向根结点。

题目2:

判断ip是否有连通性,其中连通具有传递性;

输入描述:

第一行包含两个整数n和m,表示已知的IP地址数量和连通关系数量。

接下来n行,每行包含一个字符串和一个整数,表示一个IP地址和它的编号。

接下来m行,每行包含两个整数a和b,表示IP地址对应的编号a和b之间有连通关系。

接下来一行包含一个整数q,表示需要判断连通性的IP地址数量。

接下来q行,每行包含两个字符串,表示需要判断连通性的两个 IP地址。

输出描述

对于每个需要判断连通性的IP地址对,如果它们连通,则输出"Yes",否则输出"No"。

示例1

5 3

192.168.0.1 1

192.168.0.2 2

192.168.0.3 3

192.168.0.4 4

192.168.0.5 5

1 2

2 3

4 5

3

192.168.0.1 192.168.0.2

192.168.0.2 192.168.0.3

192.168.0.3 192.168.0.4

输出:

Yes

Yes

No

cpp 复制代码
#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>

using namespace std;

// 并查集类
class UnionFind {
public:
	UnionFind(int n) {
		parent.resize(n + 1);
		rank.resize(n + 1, 0);
		for (int i = 1; i <= n; ++i) {
			parent[i] = i;
		}
	}

	// 查找集合的根节点,路径压缩优化
	int find(int x) {
		if (parent[x] != x) {
			parent[x] = find(parent[x]);
		}
		return parent[x];
	}

	// 合并两个集合,按秩合并优化
	void unite(int x, int y) {
		int rootX = find(x);
		int rootY = find(y);
		if (rootX != rootY) {
			if (rank[rootX] > rank[rootY]) {
				parent[rootY] = rootX;
			}
			else if (rank[rootX] < rank[rootY]) {
				parent[rootX] = rootY;
			}
			else {
				parent[rootY] = rootX;
				rank[rootX]++;
			}
		}
	}

private:
	vector<int> parent; // 父节点数组
	vector<int> rank;   // 秩数组 记录每个集合的"秩"或"高度"。
};

int main() {
	int n, m;
	cin >> n >> m;

	unordered_map<string, int> ipMap; // IP地址到编号的映射
	string ip;
	int id;

	// 输入n个IP地址和对应的编号
	for (int i = 0; i < n; ++i) {
		cin >> ip >> id;
		ipMap[ip] = id;
	}

	// 初始化并查集
	UnionFind uf(n);

	int a, b;
	// 输入m个连通关系
	for (int i = 0; i < m; ++i) {
		cin >> a >> b;
		uf.unite(a, b); // 将a和b所属的集合合并
	}

	int q;
	cin >> q;
	string ip1, ip2;

	// 对每个查询判断是否连通
	for (int i = 0; i < q; ++i) {
		cin >> ip1 >> ip2;
		if (uf.find(ipMap[ip1]) == uf.find(ipMap[ip2])) {
			cout << "Yes" << endl;
		}
		else {
			cout << "No" << endl;
		}
	}

	return 0;
}
相关推荐
huang5791478 分钟前
哈希算法的抗碰撞机制与安全性增强策略4
算法
林浩杨_29 分钟前
SIGIR 2026|南京大学:Video-GAR:“通过生成 Query 来验证视频语义理解”的生成增强范式
论文阅读·人工智能·算法
Logic1011 小时前
C语言/数据结构位运算题解:异或XOR找出货船中的“独特载货量“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Elsa️7461 小时前
算法一周刷题总结
c++·算法
小小程序猴11 小时前
深圳乘路资讯AI培训怎么样?课程靠谱吗?——一套课程可信度评估模型与实证分析
人工智能·算法
云上先途1 小时前
标签化服务适合哪些人?常见适用场景一次讲清
大数据·人工智能·算法·音视频
彧azz2 小时前
DFS与BFS:图遍历的两大核心算法
数据结构·学习·算法·深度优先·广度优先
宣宣猪的小花园.2 小时前
【机器学习】损失函数与梯度下降:机器如何通过“犯错”不断变好
人工智能·算法·机器学习
青山木3 小时前
Hot 100 --- 最长递增子序列
java·数据结构·算法·leetcode·动态规划
土司大王3 小时前
LeetCode hot100——33.搜索旋转排序数组:Java 二分模板与 O(log n) 实现
数据结构·算法·leetcode