C++高级数据结构之并查集

C++高级数据结构之并查集

什么是并查集

并查集(Union Find Set)是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。

并查集定义了如下的三种操作:

1、makeSet(s):建立一个新的并查集,其中包含s个单元素集合。

2、unionSet(x, y):把元素x和元素y所在的集合合并,要求x和y所在的集合不相交,如果相交则不合并。

3、find(x):找到元素x所在的集合的代表,可用于判断两个元素是否处在同一个集合中。

这三种操作的时间复杂度都不超过O(log2n),其中n是元素的个数。

并查集的实现

并查集通常采用数组来实现,如果要表示多个集合,就把这个数组当成一个森林,树的根节点表示一个集合。

int father[N]; // 父节点数组

// 初始化
for (int i = 0; i < N; i++) {
    father[i] = i;
}

// 查找
int find(int x) {
    if (father[x] != x) father[x] = find(father[x]);
    return father[x];
}

// 合并
void unionSet(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx != fy) father[fx] = fy;
}

上面的代码实现就是采用了路径压缩,每次查找时直接将x的祖先节点赋值为根节点。

并查集的应用

并查集在解决一些组团及连通性问题非常高效。

例一

LeetCode 1319 连通网络的操作次数

题目描述:

一个计算机连接网络,需要进行n次操作。每次操作选择两台已经连接到网络上的电脑x、y,并且使它们之间产生一条新的连接。如果这两台电脑已经有直接的连接或者通过其他电脑建立了连接,那么将不再重复执行连接。计算机通过网络连接后可以形成若干个分组。其中网络连接次数最少的操作顺序,输入为n对互不相同的正整数x、y,表示连接x号计算机和y号计算机。连接计算机时连接次数不超过n-1次。

输入:4

[[0,1],[0,2],[1,2]]

输出:1

解释:

先连接 0 和 1,需要一次操作。

再连接 1 和 2,需要一次操作。

总共需要 2 次操作。

代码如下:

class Solution {
public:
    int father[10005];
    int n;

    int find(int x) {
        if (father[x] != x) father[x] = find(father[x]);
        return father[x];
    }

    int makeSet() {
        int cnt = 0;
        for (int i = 0; i < n; i++) {
            father[i] = i;
            cnt++;
        }
        return cnt;
    }

    int unionSet(int x, int y) {
        int fx = find(x), fy = find(y);
        if (fx == fy) return 0;
        father[fx] = fy;
        return 1;
    }

    int makeConnected(int _n, vector<vector<int>>& connections) {
        int m = connections.size();
        n = _n;
        int groups = makeSet();
        for (int i = 0; i < m; i++) {
            groups - unionSet(connections[i][0], connections[i][1]);
        }
        if (groups > 1) return -1;
        return m - (n - 1);
    }
};

例二

P4003 [NOI2011]修建道路

题目描述:

小明所在的城市有n个交叉路口,它们之间有m条道路相连。如果两个路口之间有一条以上的道路相连,就认为它们之间的道路路况比较拥挤。现在小明受委托要对这些道路中的某些道路进行改造,以减少道路障碍,使得道路拥挤程度最低。

输入格式
第一行输入整数n,m,表示交叉路口数和道路条数。

接下来m行,每行输入两个整数x,y,表示x,y之间有一条双向的道路。

输出格式
一行输出一个整数,表示改造完毕后道路的拥挤程度。

数据范围
2≤n≤20000,
m≤100000

输入样例:
5 6
1 2
1 3
1 4
1 5
2 3
3 4
输出样例:
1

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 20010, M = 100010;

int n, m;
int p[N], cnt[N];

struct Edge {
    int a, b;
}edges[M];

int find(int x) {
    if (x != p[x]) p[x] = find(p[x]);
    return p[x];
}

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

    for (int i = 1; i <= n; i++) p[i] = i, cnt[i] = 1;

    for (int i = 0; i < m; i++) cin >> edges[i].a >> edges[i].b;

    int res = n;

    for (int i = 0; i < m; i++) {
        int a = edges[i].a, b = edges[i].b;
        if (find(a) != find(b)) {
            p[find(a)] = find(b);
            cnt[find(b)] += cnt[find(a)];
            res--;
        }
    }

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (p[i] == i) ans = max(ans, cnt[i]);
    }

    cout << res - ans << endl;

    return 0;
}

总结

并查集非常适用于组团和连通性问题,在$O(log_2n)$的时间复杂度内可以完成查找、合并两个集合、判断两个节点是否在同一个集合中的操作。在实现时,采用路径压缩的方法,可以大大提高并查集的效率。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++高级数据结构之并查集 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 多维度深入分析Redis的5种基本数据结构

    多维度深入分析Redis的5种基本数据结构 Redis是一种高性能、内存数据存储系统,它支持多种数据结构,包括字符串、哈希表、列表、集合和有序集合。其中,每种数据结构都具有不同的特性和用途,本文将对这五种基本数据结构进行深入分析。 1. 字符串(string) 字符串是最基本的数据结构,一个字符串可以存储任意二进制数据,例如一个jpg图片或者一个序列化的对象…

    数据结构 2023年5月17日
    00
  • Redis数据结构之链表与字典的使用

    Redis是一个开源、基于内存的数据结构存储系统。Redis支持多种数据类型,包括字符串、整数、浮点数、列表、哈希表、集合、有序集合等。本文将详细介绍Redis数据结构之链表与字典的使用。 链表 链表是Redis中常用的数据结构之一,主要用于存储有序的元素列表。链表中的每个元素都包含了一个指向前驱元素和后继元素的指针,这种结构可以方便地实现链表的插入、删除和…

    数据结构 2023年5月17日
    00
  • Java数据结构顺序表的详细讲解

    Java数据结构顺序表的详细讲解 什么是顺序表? 顺序表是一种线性结构,它通过一段连续的存储空间来存储一组元素,每个元素占用一个固定大小的存储单元,元素之间按照一定的顺序紧密排列。 顺序表的实现 在Java中,顺序表可以通过数组实现。数组是一种非常基础的数据结构,它可以用来存储相同类型的数据,数组元素的地址是连续的,因此可以通过下标访问数组中的元素。 实现步…

    数据结构 2023年5月17日
    00
  • C++ 数据结构二叉树(前序/中序/后序递归、非递归遍历)

    下面是关于C++二叉树数据结构的详细攻略。 什么是二叉树 二叉树是一种树形数据结构,每个节点最多有两个子节点:左节点和右节点。一个节点没有左节点或右节点则分别为左子树和右子树为空。 递归遍历二叉树 前序遍历 前序遍历是指对于一棵二叉树,在访问右子树之前,先访问根节点,然后访问左子树。 下面是C++递归遍历二叉树的前序遍历示例代码: template <…

    数据结构 2023年5月17日
    00
  • Java数据结构之图的基础概念和数据模型详解

    Java数据结构之图的基础概念和数据模型详解 简介 图是一种非常重要的数据结构,在计算机科学和实际应用中广泛使用。比如搜索引擎中的网页之间的链接关系就可以用图来表示和处理。在本文中,我们将详细讲解图的基础概念和数据模型。同时,我们将通过两个实例来进一步说明图的应用。 图的基础概念 什么是图 图是由若干个节点(顶点)和连接节点的边组成的一种数据结构。一个图可以…

    数据结构 2023年5月17日
    00
  • java编程队列数据结构代码示例

    下面是“Java编程队列数据结构代码示例”的完整攻略。 什么是队列 队列是一种有序的数据结构,特点是先进先出(FIFO)。队列中不管是插入操作还是删除操作,都是在队列的两端进行的,插入操作在队列的尾部进行,删除操作在队列的头部进行。队列的一个重要用途是在计算机的操作系统中,实现进程和所有需要等待资源的实体之间的交互。 队列的实现 队列数据结构可以采用数组或链…

    数据结构 2023年5月17日
    00
  • C语言线性表的顺序表示与实现实例详解

    C语言线性表的顺序表示与实现实例详解 1. 线性表的定义 线性表是一种线性结构,它是由n个数据元素(n≥0)组成的有限序列。当n=0时,我们称为一个空表。 在C语言中,我们可以通过数组来实现线性表的顺序表示,每个数据元素都存在数组的一个位置中,数组下标可以看作是该数据元素的位置。 2. 线性表的基本操作 一个线性表的基本操作有以下几种: 2.1 初始化线性表…

    数据结构 2023年5月17日
    00
  • AtCoder Beginner Contest 299

    A – Treasure Chest (abc299 a) 题目大意 给定一个包含 |*.的字符串,其中|两个,*一个,问*是否在两个|之间。 解题思路 找到两个|的下标\(l, r\)以及 *的下标\(mid\),看看是否满足 \(l < mid < r\)即可。 神奇的代码 #include <bits/stdc++.h> usi…

    算法与数据结构 2023年4月23日
    00
合作推广
合作推广
分享本页
返回顶部