C语言实现并查集
导读
大家好,很高兴又和大家见面啦!!!
在上一篇内容中我们从数据结构的三要素初步认识了并查集这种数据结构,但是上一篇对并查集的介绍并不准确。
那我们对并查集的认识存在哪些错误呢?我们又应该如何实现并查集呢?在今天的内容中,我们将会从数据结构的三要素出发,进一步学习并实现并查集。
一、并查集的定义
并查集是一种高效管理不相交集合的数据结构,专门解决动态连通性问题。它通过树形结构组织集合元素,支持以下核心操作:
- 查询(Find):判断两个元素是否属于同一集合
- 合并(Union):将两个不相交的集合合并为一个集合
1.1 定义解析
并查集是一种高效管理不相交集合的数据结构
从第一句话的前部分中,我们需要提取3个关键信息:
- 高效管理
- 不相交集合
- 数据结构
在上一篇内容中,我们认识了并查集是一种数据结构,其逻辑结构是集合,但是为什么说并查集是高效管理呢?
这是因为在实际的使用过程中,我们通过对并查集实现优化后能够做到近似常数级的时间复杂度。具体如何实现,后面我们会继续介绍,这里先不展开。
这里说的高效管理不相交集合实际上是指并查集中各个不相交的子集。
专门解决动态连通性问题
在第一句话的后半部分中,我们需要理解什么是动态连通性问题。
简单来说,就是查询两个元素是否连通,对两个不联通的元素建立连通关系。这也就是我们所说的查找与合并。
通过树形结构组织集合元素
这里所说的树形结构与传统的树形结构是有区别的:
- 传统的树形结构就是我们前面学的递归结构,每一个结点都会通过其孩子指针指向孩子结点
- 并查集中子集的树形结构并不属于递归结构,它是由每个结点的双亲指针指向该结点的父结点
现在我们从定义出发,对并查集做出了一个更详细的介绍,下面我们继续来看一下并查集这种数据结构的三要素。
二、逻辑结构
并查集在逻辑上是由各棵不相交的子集组成的集合,子集中的元素在逻辑上呈现树形结构,每棵树的根结点作为子集的代表元素。
三、存储结构
在上一篇内容中,我们介绍了两种并查集的存储结构——顺序存储和链式存储。
但是上一篇的介绍是基于我们对并查集的初步理解而实现的,因此上一篇中提到的两种存储方式显然不能更加准确的表示并查集。
那对于并查集这个数据结构,我们又应该使用怎样的存储结构呢?下面我们就来分析一下;
3.1 树与森林的存储结构
在树与森林中,常用的存储结构有3种:
- 双亲表示法:通过顺序存储实现,每个结点中存放结点数据信息与双亲位置信息;
//双亲表示法
typedef struct ParentNode {
ElemType data; // 数据域
int parent; // 双亲域
}PNode;//双亲结点
typedef struct Parent {
PNode* list;//通过顺序表实现
int n;//结点数量
}PTree;//双亲树
- 孩子表示法:通过顺序表+链表实现,每个结点中存放结点数据与指向孩子链表的指针,孩子链表中存放孩子的位置信息;
//孩子表示法
typedef struct ChildNode {
int pi;//孩子位置信息
struct ChildNode* next_child;//孩子指针
}CNode;//孩子结点
typedef struct ParentNode {
ElemType data;//结点数据域
CNode* child;//孩子指针域
}PN;//双亲结点
typedef struct ChildTree