算法知识点———并查集

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

合并(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;
}
相关推荐
jiao0000120 分钟前
数据结构——队列
c语言·数据结构·算法
kaneki_lh24 分钟前
数据结构 - 栈
数据结构
铁匠匠匠24 分钟前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
C-SDN花园GGbond26 分钟前
【探索数据结构与算法】插入排序:原理、实现与分析(图文详解)
c语言·开发语言·数据结构·排序算法
迷迭所归处1 小时前
C++ —— 关于vector
开发语言·c++·算法
leon6252 小时前
优化算法(一)—遗传算法(Genetic Algorithm)附MATLAB程序
开发语言·算法·matlab
CV工程师小林2 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
Navigator_Z2 小时前
数据结构C //线性表(链表)ADT结构及相关函数
c语言·数据结构·算法·链表
还听珊瑚海吗2 小时前
数据结构—栈和队列
数据结构
Aic山鱼2 小时前
【如何高效学习数据结构:构建编程的坚实基石】
数据结构·学习·算法