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

yizhihongxing

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日

相关文章

  • MySQL优化及索引解析

    MySQL是业界常用的关系型数据库管理系统之一,作为程序员,我们需要了解如何对MySQL进行优化,以提高数据库的性能。下面是MySQL优化及索引解析的完整攻略。 目录 优化查询语句 优化数据库设计 优化服务器架构 索引优化 实例分析 优化查询语句 查询语句是应用程序与数据库之间的桥梁,优化查询语句可以大大提高数据库的性能。以下是一些优化查询语句的方法: 使用…

    数据结构 2023年5月17日
    00
  • 【华为OD机试 2023】专栏介绍 +华为OD机试介绍+ 真题目录【转载】

    华为题库说明 2022与2023题库的区别 华为OD机试的题库是季度更新的(Q1\Q2\Q3\Q4)。笔者专栏的题库分为2023和2022。 2023的题库是包括2022.11(Q4第四季度)之后以及2023年的题库。 2022的题库是包括2022.11(Q4第四季度)之前题库。 支持的语言 目前大部分题 使用C++ Java JavaScript 以及py…

    算法与数据结构 2023年4月17日
    00
  • 带你了解Java数据结构和算法之高级排序

    带你了解Java数据结构和算法之高级排序攻略 什么是高级排序算法? 在计算机科学中,排序算法是将一串数据按照特定顺序进行排列的一种算法。根据数据规模、数据类型、稳定性、时间复杂度以及空间复杂度等因素,排序算法分为许多种类。高级排序算法是相对于普通排序算法而言,其时间复杂度更低、排序速度更快、稳定性更高的算法。 高级排序算法的分类及特点 高级排序算法分为内排序…

    数据结构 2023年5月17日
    00
  • 贪心算法基础及leetcode例题

    理论 本质:找到每个阶段的局部最优,然后去推导得到全局最优两个极端:常识&&很难: 很多同学通过了贪心的题目,但都不知道自己用了贪心算法,因为贪心有时候就是常识性的推导,所以会认为本应该就这么做! 套路:贪心没有套路,说白了就是常识性推导加上举反例做题的时候,只要想清楚 局部最优 是什么,如果推导出全局最优,其实就够了。 贪心算法一般分为如下…

    算法与数据结构 2023年4月20日
    00
  • C++数据结构与算法之双缓存队列实现方法详解

    C++数据结构与算法之双缓存队列实现方法详解 引言 在实际开发中,双缓存队列是一个非常常见的数据结构,主要用来解决多线程情况下的数据同步问题。本篇文章将详细介绍如何使用C++语言实现双缓存队列。 双缓存队列简介 双缓存队列是一种常用的同步数据结构,它并非一个标准库中的容器,通常需要手动实现。双缓存队列维护着两个缓存区,一个当前使用的缓存区,一个需要被更新的缓…

    数据结构 2023年5月17日
    00
  • Python数据结构与算法的双端队列详解

    Python数据结构与算法的双端队列详解 双端队列(deque)是一种具有队列和栈的性质的数据结构。与队列和栈不同的是双端队列允许从两端添加和删除元素。Python语言中内置了deque模块,使得在实现双端队列时更加方便快捷。 1.双端队列基本操作 from collections import deque # 创建双端队列 d = deque() # 在队…

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

    A – N-choice question (abc300 a) 题目大意 给定一个元素互不相同的数组\(c\)和 \(a,b\),找到 \(i\)使得 \(c_i = a + b\) 解题思路 直接for循环寻找即可。 神奇的代码 #include <bits/stdc++.h> using namespace std; using LL = …

    算法与数据结构 2023年4月30日
    00
  • JavaScript数据结构和算法之二叉树详解

    JavaScript数据结构和算法之二叉树详解 什么是二叉树? 二叉树是一种树形结构,其中每个节点最多有两个子节点:左子节点和右子节点。每个节点都是一个对象,包括属性和方法。节点的属性可能包括值,左节点和右节点。节点的方法可能包括插入和删除。 二叉树的应用场景 二叉树的常用场景包括: 排序算法(二叉排序树); 表达式求值; 线段树; 图形图像学; 数据压缩算…

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