算法知识点———并查集

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

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

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

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

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

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

然后如果1和3这条边想合并的时候只需要合并1的父结点和3的父结点即可,也就是1的父结点是4.这样01234都在一个集合里面,也就是说root[0] == root[2] 表示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;
}
相关推荐
前端炒粉3 小时前
35.LRU 缓存
开发语言·javascript·数据结构·算法·缓存·js
断剑zou天涯5 小时前
【算法笔记】窗口内最大值或最小值的更新结构
java·笔记·算法
smj2302_796826525 小时前
解决leetcode第3753题范围内总波动值II
python·算法·leetcode
骑着猪去兜风.7 小时前
线段树(二)
数据结构·算法
fengfuyao9858 小时前
竞争性自适应重加权算法(CARS)的MATLAB实现
算法
散峰而望8 小时前
C++数组(二)(算法竞赛)
开发语言·c++·算法·github
leoufung8 小时前
LeetCode 92 反转链表 II 全流程详解
算法·leetcode·链表
靠沿8 小时前
Java数据结构初阶——Collection、List的介绍与ArrayList
java·数据结构·list
wyhwust9 小时前
交换排序法&冒泡排序法& 选择排序法&插入排序的算法步骤
数据结构·算法·排序算法
利刃大大9 小时前
【动态规划:背包问题】完全平方数
c++·算法·动态规划·背包问题·完全背包