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日

相关文章

  • C语言数据结构之vector底层实现机制解析

    C语言数据结构之vector底层实现机制解析 什么是vector? vector是C++标准库中的一种容器,可以动态调整大小,用于存储数据。 vector的底层实现机制 vector实际上是通过数组实现的,当需要添加元素时,如果当前数组已满,就会重新创建一个更大的数组,并将原数组中的元素复制到新数组中。这样,内存空间得到了增加,同时操作后的元素仍然是顺序存储…

    数据结构 2023年5月17日
    00
  • C++ 二叉树的实现超详细解析

    C++ 二叉树的实现超详细解析 在本篇文章中,我们将详细讲解如何使用C++语言实现二叉树数据结构。我们将分为以下几个部分: 二叉树的定义 二叉树的基本操作 C++实现 1. 二叉树的定义 二叉树是一种树形数据结构,其中每个节点最多有两个子节点。二叉树有以下几个特点: 树中的每个节点最多有两个子节点 左子节点的键值比父节点的键值小 右子节点的键值比父节点的键值…

    数据结构 2023年5月17日
    00
  • Java数据结构之堆(优先队列)的实现

    Java 数据结构之堆(优先队列)的实现 什么是堆(优先队列) 堆(Heap)是一种数据结构,使用数组实现。堆分为小根堆和大根堆,大根堆满足父节点值大于子节点,小根堆则相反。堆通常被用来实现优先队列(Priority Queue)。 优先队列(Priority Queue)是一个能够让用户迅速查找到队列中最小值(或最大值)的抽象数据类型(ADT)。优先队列通…

    数据结构 2023年5月17日
    00
  • C#数据结构与算法揭秘四 双向链表

    C#数据结构与算法揭秘四 双向链表 简介 本文将讲解如何在C#中实现双向链表。双向链表是一种常用的数据结构,在许多算法中都有广泛应用,它提供了与单向链表不同的灵活性和便利性。 双向链表的实现 创建一个双向节点 双向链表由节点(Node)组成。一个节点包含两个指针:一个指向前一个节点,一个指向后一个节点。由于这两个指针都可能为null,所以我们将它们声明为可空…

    数据结构 2023年5月17日
    00
  • C#数据结构与算法揭秘二 线性结构

    C#数据结构与算法揭秘二 线性结构 线性结构是指数据元素之间一对一的关系,即数据元素之间存在一个前驱和一个后继。一般有两种基本形式:线性表和栈、队列。 线性表 线性表是由同类型数据元素构成有序序列的线性结构,常被用于实现基于数组的数据结构,如向量、矩阵等。 线性表可以分为顺序表和链表两种。 顺序表(Sequence List):是把线性表的元素按照顺序存储在…

    数据结构 2023年5月17日
    00
  • Codeforces Round 871 (Div. 4)

    A.Love Story 题意: 给定n个长度为10的字符串,问其与codeforces字符串的对应下标字母不同的个数。 分析: 对于每个字符串从前往后依次和“codeforces”对应字符比较然后统计不同字母数即可 code: #include <bits/stdc++.h> using namespace std; int main() { …

    算法与数据结构 2023年5月8日
    00
  • Java数据结构之队列(动力节点Java学院整理)

    Java数据结构之队列(动力节点Java学院整理) 队列是一种有序列表,在其中所有插入操作必须在后端进行,而所有的删除操作必须在前端进行的数据结构。这种结构有时被称为先进先出(FIFO)。 队列的分类 普通队列:队列和栈一样,都是只能在一端进行插入操作,在另一端进行删除操作的特殊线性表。队列的特点是:先进先出。适用于数据必须按照插入顺序处理的必要场合。 双端…

    数据结构 2023年5月17日
    00
  • golang优先级队列的实现全过程

    下面是关于”golang优先级队列的实现全过程”的详细讲解。 什么是优先级队列? 优先级队列是一种常用的数据结构,它可以帮我们按照一定规则(即优先级)将元素按照大小排序,并支持快速插入、删除和查询最大或最小的元素等操作。我们可以将优先级队列想象成一个具有优先级的、自动排序的队列,其中优先级高的元素(比如数字大的元素)排在前面,优先级低的元素(比如数字小的元素…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部