当前位置: 首页 > news >正文

并查集理论以及实现

一, 并查集理解

1.并查集-部落

简单说是一个只用于不交集的合并、查找,其他的操作没啥意义,看似和树没啥关系,实际操作中我们会用树来进行一个结构优化。

并查集可以理解为一个部落,部落的每个元素是个村庄,村庄之间有的可以互通,所有互通的村庄的集合就是一个部落,而每个部落都会有个代表村庄,也可以说是老大。

2.并查集操作

a.查找,查找元素是属于哪个集合,通常返回这个集合的代表元素,其目的是为了判断两个元素是否同属于一个集合

b.合并,将两个集合合并为一个集合

3.并查集两种实现思路

a.Quick find

如果只进行一次合并,后面都是查找,就使用这种

查找效率:O(1)  组合效率:O(N)

每一个元素,可以有个标号,代表这个元素的老大,当改变这个元素的老大,则这个元素的小弟也会认这个元素的老大做大哥

如图例:初始化时每个元素的老大是自己,将0、4合并后0认4做老大,0元素下标改成4

再将4、2合并后4认2做老大,以及4元素的小弟也要认2做老大,也就是把所有下标是4的都改成2

b.Quick union

适合组合频率高,查找频率低

查找效率:O(logN)  组合效率:O(logN)

看到时间复杂度为logN的结构应该对树要敏感,而Quickunion的核心就是树结构,当初始化时元素指向自己

假如我们将0、1组合此时0指向1,再将2、0组合,此时2指向0。

如果我们要查找2所在集合需要从2找到0再从0找到1,查找的集合就是他们的根,查找效率为整棵树的高度logN

如果我们要合并3和2,合并的其实是他们所在集合的根,也就是把4的下标改为1,合并他们根的过程就是从2找到1,然后从3找到4,最后将4和1合并

 

 注意我们代码实现还需要一张size表,用来存储对应树的节点个数,初始化时每个节点的size为1

如果合并0、1,此时0的parentID为1,而1的是根节点就更新1的size为2

 

当我们把2、4合并,4的size变为2

再把4、3合并,3的size就为3

最后把1、3合并,3的size就为5 

二、QuickFind代码实现

1.头文件中的接口

//
// Created by 27893 on 2025/7/12.
//#pragma once
typedef int Element_t;
//
// Created by 27893 on 2025/7/12.
//#pragma once
#include "UnionFindSet.h"
typedef struct {int n;Element_t*data;int*groupID;
}QFSet_t;QFSet_t*createQFSet(int n);
int initQFSet(QFSet_t*set,Element_t*data,int n);
int releaseQFSet(QFSet_t*set);int unionQFSet(QFSet_t*set,Element_t a,Element_t b);int isSameQFSet(QFSet_t*set,Element_t a,Element_t b);

2.将头文件中的接口一一实现

//
// Created by 27893 on 2025/7/12.
//
#include <string.h>
#include <stdlib.h>
#include "QuickFindSet.h"#include <stdio.h>QFSet_t * createQFSet(int n) {QFSet_t*set=malloc(sizeof(QFSet_t));if(set==NULL)return NULL;set->n=n;set->data=malloc(sizeof(Element_t)*n);set->groupID=malloc(sizeof(int)*n);if(set->data==NULL||set->groupID==NULL) {free(set->data);return NULL;}memset(set->data,0,sizeof(Element_t)*n);memset(set->groupID,0,sizeof(int)*n);return set;
}int initQFSet(QFSet_t *set, Element_t *data, int n) {if(set==NULL||data==NULL)return 0;n=set->n<n?set->n:n;for (int i=0;i<n;i++) {set->data[i]=data[i];set->groupID[i]=i;}return 1;
}int releaseQFSet(QFSet_t *set) {if(set==NULL)return 0;free(set->data);free(set->groupID);free(set);return 1;
}static int findIndex(const QFSet_t*set,Element_t data) {for (int i=0;i<set->n;i++) {if (set->data[i]==data)return i;}return -1;
}int isSameQFSet(QFSet_t *set, Element_t a, Element_t b) {//找到a和b的索引int aindex=findIndex(set,a);int bindex=findIndex(set,b);if(aindex==-1||bindex==-1)return 0;//比较这两个值在groupID中是否相等return set->groupID[aindex]==set->groupID[bindex];
}int unionQFSet(QFSet_t *set, Element_t a, Element_t b) {//1.找到a和b的索引,比较这两个值在groupID中是否相等int aindex=findIndex(set,a);int bindex=findIndex(set,b);if(aindex==-1||bindex==-1)return 0;//2.不相等就把和a的groupID相同的元素的groupID改成b的groupIDint groupID=set->groupID[aindex];for (int i=0;i<set->n;i++) {if (set->groupID[i]==groupID) {set->groupID[i]=set->groupID[bindex];}}printf("union %d and %d\n",a,b);return 1;
}

3.测试代码是否有bug

 按照左图中的结构进行测试,或者自己模拟数据进行测试

//
// Created by 27893 on 2025/7/12.
//
#include <stdio.h>
#include "QuickFindSet.h"
void test() {int n=9;QFSet_t*set=createQFSet(n);Element_t data[]={0,1,2,3,4,5,6,7,8};initQFSet(set,data,n);unionQFSet(set,3,4);unionQFSet(set,8,0);unionQFSet(set,2,3);unionQFSet(set,5,6);if (isSameQFSet(set,0,2)) {printf("yes\n");}else {printf("no\n");}if (isSameQFSet(set,2,4)) {printf("yes\n");}else {printf("no\n");}unionQFSet(set,5,1);unionQFSet(set,7,3);unionQFSet(set,1,6);unionQFSet(set,4,8);if (isSameQFSet(set,0,2)) {printf("yes\n");}else {printf("no\n");}if (isSameQFSet(set,2,4)) {printf("yes\n");}else {printf("no\n");}releaseQFSet(set);
}
int main() {test();return 0;
}

 明天我们再把QuickUnion实现

http://www.dtcms.com/a/276568.html

相关文章:

  • QILSTE/旗光 H6-108QHR
  • SSM项目上传文件的方式及代码
  • Java使用Langchai4j接入AI大模型的简单使用(二)
  • 线程同步:互斥锁与条件变量实战指南
  • 猿人学js逆向比赛第一届第二十题
  • 关于赛灵思的petalinux zynqmp.dtsi文件的理解
  • 二叉树算法进阶
  • 《Spring 中上下文传递的那些事儿》Part 8:构建统一上下文框架设计与实现(实战篇)
  • 深入理解设计模式之工厂模式:创建对象的艺术
  • Pandas 模块之数据的读取
  • 暑期前端训练day6
  • 【人工智能99问】开篇!
  • 【leetcode】1757. 可回收且低脂的产品
  • FastAdmin项目开发三
  • Python数据容器-集合set
  • 什么是 Bootloader?怎么把它移植到 STM32 上?
  • 关于两种网络攻击方式XSS和CSRF
  • 车载操作系统 --- Linux实时化与硬实时RTOS综述
  • 格密码--数学基础--06对偶空间与对偶格
  • 建造者模式(Builder)
  • Python 实战:构建可扩展的命令行插件引擎
  • Java 方法重载与构造器
  • 【Python练习】039. 编写一个函数,反转一个单链表
  • CSP-S 模拟赛 10
  • pytest自动化测试框架实战
  • 【王树森推荐系统】行为序列01:用户历史行为序列建模
  • Java责任链模式实现方式与测试方法
  • Python爬虫实战:研究xlwt 和 xlrd 库相关技术
  • 【理念●体系】迁移复现篇:打造可复制、可复原的 AI 项目开发环境k
  • 笔试题库 | 亿纬锂能社招大易笔试测评题库考点分析及真题整理