首页 > 其他分享 >3.9.并查集

3.9.并查集

时间:2025-01-22 15:30:06浏览次数:3  
标签:元素 ListNode int 查集 链表 集合 节点 3.9

并查集

并查集是一种用于处理不相交集合的合并与查询问题的数据结构,在 C++ 中有着广泛的应用,以下是关于 C++ 中并查集的详细介绍:

基本概念

  • 集合表示:并查集将每个集合用一棵树来表示,树中的节点代表集合中的元素,树根作为集合的代表元素。
  • 合并操作:把两个集合合并为一个集合,通过将一个集合的树根连接到另一个集合的树根来实现。
  • 查询操作:查询两个元素是否属于同一个集合,通过判断它们的树根是否相同来确定。

实现方式

  • 数组实现
    • 原理:用一个数组parent来存储每个元素的父节点。初始化时,每个元素的父节点设为其自身,表示每个元素都在独立的集合中。合并操作时,将一个集合的根节点的父节点设置为另一个集合的根节点。查询操作时,通过不断查找元素的父节点,直到找到根节点,来判断两个元素是否在同一集合。
    • 代码示例
#include <iostream>
#include <vector>

class UnionFind {
private:
    // 存储每个元素的父节点
    std::vector<int> parent;

public:
    // 初始化并查集
    UnionFind(int n) : parent(n) {
        for (int i = 0; i < n; ++i) {
            // 初始时每个元素的父节点是它自己
            parent[i] = i;
        }
    }

    // 查找元素x的根节点
    int find(int x) {
        // 路径压缩,使查找路径上的节点直接连接到根节点
        while (x!= parent[x]) {
            // 路径压缩优化,将x的父节点更新为父节点的父节点
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    // 合并元素x和y所在的集合
    void unionSet(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX!= rootY) {
            // 将y的根节点设置为x的根节点
            parent[rootY] = rootX;
        }
    }

    // 判断元素x和y是否在同一集合
    bool connected(int x, int y) {
        return find(x) == find(y);
    }
};

int main() {
    // 初始化并查集,有5个元素
    UnionFind uf(5);
    // 合并元素1和2所在的集合
    uf.unionSet(1, 2);
    // 合并元素3和4所在的集合
    uf.unionSet(3, 4);
    // 输出元素1和2是否在同一集合,是则输出true,否则输出false
    std::cout << "Are 1 and 2 connected? " << (uf.connected(1, 2)? "true" : "false") << std::endl;
    // 输出元素1和3是否在同一集合,是则输出true,否则输出false
    std::cout << "Are 1 and 3 connected? " << (uf.connected(1, 3)? "true" : "false") << std::endl;
    return 0;
}
  • 链表实现
    • 原理:每个集合用一个链表来表示,链表的头节点作为集合的代表元素。合并操作时,将一个链表连接到另一个链表的尾部。查询操作时,遍历链表来判断两个元素是否在同一链表中。
    • 代码示例
#include <iostream>

// 链表节点结构体
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class UnionFind {
private:
    // 存储每个元素所在链表的头节点
    ListNode** heads;

public:
    UnionFind(int n) {
        // 初始化头节点数组
        heads = new ListNode*[n];
        for (int i = 0; i < n; ++i) {
            // 每个元素初始时都有自己的链表,头节点为自己
            heads[i] = new ListNode(i);
        }
    }

    // 查找元素x所在链表的头节点
    ListNode* find(int x) {
        return heads[x];
    }

    // 合并元素x和y所在的集合
    void unionSet(int x, int y) {
        ListNode* headX = find(x);
        ListNode* headY = find(y);
        if (headX!= headY) {
            // 将y所在的链表连接到x所在链表的尾部
            ListNode* cur = headX;
            while (cur->next!= nullptr) {
                cur = cur->next;
            }
            cur->next = headY;
            // 更新y所在链表的头节点为x所在链表的头节点
            heads[y] = headX;
        }
    }

    // 判断元素x和y是否在同一集合
    bool connected(int x, int y) {
        return find(x) == find(y);
    }

    ~UnionFind() {
        // 释放链表节点内存
        for (int i = 0; i < n; ++i) {
            ListNode* cur = heads[i];
            ListNode* next;
            while (cur!= nullptr) {
                next = cur->next;
                delete cur;
                cur = next;
            }
        }
        delete[] heads;
    }
};

int main() {
    // 初始化并查集,有5个元素
    UnionFind uf(5);
    // 合并元素1和2所在的集合
    uf.unionSet(1, 2);
    // 合并元素3和4所在的集合
    uf.unionSet(3, 4);
    // 输出元素1和2是否在同一集合,是则输出true,否则输出false
    std::cout << "Are 1 and 2 connected? " << (uf.connected(1, 2)? "true" : "false") << std::endl;
    // 输出元素1和3是否在同一集合,是则输出true,否则输出false
    std::cout << "Are 1 and 3 connected? " << (uf.connected(1, 3)? "true" : "false") << std::endl;
    return 0;
}

应用场景

  • 连通性问题:如判断网络中的节点是否连通,城市之间的道路是否连通等。
  • 图的最小生成树:在 Kruskal 算法中,用于判断边的两个端点是否在不同的连通分量中,以避免形成环。
  • 社交网络分析:判断两个人是否在同一个朋友圈子中,或者将具有共同朋友的人划分到同一个社交圈子里。

标签:元素,ListNode,int,查集,链表,集合,节点,3.9
From: https://blog.csdn.net/m0_60046831/article/details/145304422

相关文章

  • 并查集重温
    普通并查集 板子:voidfind(intx){ if(f[x]==x)returnx; returnf[x]=find(f[x]);}voidmerge(intx,inty){ intfx=find(x),fy=find(fy); if(fx!=fy)f[fx]=fy;} 具体几个应用:1.找图中联通块的个数 扩展一下,问图最小需要多少条边联通。  原题......
  • 并查集(食物链,奶酪)
    食物链  题目  提交记录  讨论  题解  视频讲解动物王国中有三类动物 A,B,CA,B,C,这三类动物的食物链构成了有趣的环形。AA 吃 BB,BB 吃 CC,CC 吃 AA。现有 NN 个动物,以 1∼N1∼N 编号。每个动物都是 A,B,CA,B,C 中的一种,但是我们并不知道它到......
  • 江南鹤微信hook最新版 3.9.12.15功能列表
    详询微信weixinhook主动调用登录刷新登录二维码注销登录退出微信当前登录帐号信息联系人获取好友列表获取指定好友信息获取好友简要信息_协议获取好友详细信息_协议指量获取好友信息_协议修改好友备注添加好友分享的名片同意加好友请求删除好友搜索微信用户添......
  • 修复公路(并查集)
    题目链接:https://www.luogu.com.cn/problem/P1111题意:有n个村,给你m个信息,1个信息包含存在道路的两个村子以及通路的时间,让你求是否每个村子都能相连,若能相连输出通路最短时间思路:并查集+排序在一个集合中的村子能够相互连通,所以就看本来并查集n个独立的集合能不能通过所给操......
  • 洛谷P1525 [NOIP2010 提高组] 关押罪犯(种子并查集基础)
    题目链接:P1525[NOIP2010提高组]关押罪犯-洛谷|计算机科学教育新生态题目难度:普及+/提高题目描述:S城现有两座监狱,一共关押着 N 名罪犯,编号分别为 1∼N,有m对罪犯,每对之间有仇恨值,问如何分配罪犯使得现Z市长要看到其中最大的矛盾值最小。输入格式:每行中两个数之......
  • Royal Elementor Addons Pro v1.3.987 + v1.5.0 elementor网页设计元素组件插件下载
    RoyalElementorAddonsProelementor网页设计元素组件插件破解版简介&下载RoyalElementorAddonsProNulledElementor小部件、模板套件和扩展。从零到英雄构建网站所需的唯一Elementor插件!动态网站生成器建立任何类型的网站:使用Elementor动态标签创建自定义帖子类型创......
  • 并查集
    并查集模板:#include<iostream>#include<vector>usingnamespacestd;//初始化父节点数组vector<int>fa;//查找根节点并进行路径压缩intfindParent(intx){if(x==fa[x])returnx;returnfa[x]=findParent(fa[x]);}//合并两个集合voidunionS......
  • 带权并查集
    #include<bits/stdc++.h>usingnamespacestd;#defineendl'\n'#definexfirst#defineysecond#defineintlonglongconstintN=1e6+10,mod=998244353;intf[N],w[N];//w[i]表示i这个点比根节点的值大多少intfind(intx){ if(f[x]==x)returnx; intp......
  • 微软edge浏览器 v131.0.2903.99便携版
    点击上方蓝字睿共享关注我前言MicrosoftEdge浏览器是个新浏览器,它用起来很简单,界面也很清爽。这个浏览器功能特别多,里面还带了微软的小助手Contana,能帮用户做不少贴心的事儿。它支持安装各种小工具(插件),还能在网页上做标记。而且,管理网页标签也变得很容易,不用离开当前看的网页,就......
  • docker环境利用centos7镜像 + miniconda + python3.9 + wkhtmltopdf 构建html转图片服
    1、目录结构html2image——Dockerfile——main.py——requirements.txt2、DockerfileFROMcentos:7WORKDIR/appCOPY./app/RUNcurl-Ohttps://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.centos7.x86_64.rpm\&&curl......