当前位置:   article > 正文

C语言经典算法之并查集_c语言并查集

c语言并查集

目录

前言

A.建议

B.简介

一 代码实现

二 时空复杂度

A.查找操作(Find):

B.合并操作(Union):

三 优缺点

A.优点:

B.缺点:

C.总结:

四 现实中的应用


前言

A.建议

1.学习算法最重要的是理解算法的每一步,而不是记住算法。

2.建议读者学习算法的时候,自己手动一步一步地运行算法。

tips:文中的(如果有)对数,则均以2为底数

B.简介

并查集(Disjoint Set Union,简称并查集,也叫不相交集合)是一种用来管理分组的数据结构。它主要支持两种操作:查找(Find)和合并(Union)。并查集通常用于处理元素的分组问题,比如连通性的问题,网络连接状态的问题等。

一 代码实现

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义并查集结构体
  4. typedef struct {
  5. int *parent; // 父节点数组
  6. int *rank; // 秩(用于优化合并操作)
  7. int size; // 并查集的大小
  8. } DisjointSet;
  9. // 初始化并查集
  10. void initDisjointSet(DisjointSet *set, int size) {
  11. set->size = size;
  12. set->parent = (int *)malloc(sizeof(int) * size);
  13. set->rank = (int *)malloc(sizeof(int) * size);
  14. // 初始化每个元素的父节点为自身,秩为0
  15. for (int i = 0; i < size; i++) {
  16. set->parent[i] = i;
  17. set->rank[i] = 0;
  18. }
  19. }
  20. // 查找操作(找到元素所在的集合的代表元素)
  21. int find(DisjointSet *set, int x) {
  22. if (set->parent[x] != x) {
  23. // 路径压缩:将节点的父节点直接设为根节点,减小查找路径长度
  24. set->parent[x] = find(set, set->parent[x]);
  25. }
  26. return set->parent[x];
  27. }
  28. // 合并操作
  29. void unionSets(DisjointSet *set, int x, int y) {
  30. int rootX = find(set, x);
  31. int rootY = find(set, y);
  32. // 按秩合并:将秩较小的集合合并到秩较大的集合上
  33. if (rootX != rootY) {
  34. if (set->rank[rootX] < set->rank[rootY]) {
  35. set->parent[rootX] = rootY;
  36. } else if (set->rank[rootX] > set->rank[rootY]) {
  37. set->parent[rootY] = rootX;
  38. } else {
  39. set->parent[rootY] = rootX;
  40. set->rank[rootX]++;
  41. }
  42. }
  43. }
  44. // 释放并查集占用的内存
  45. void freeDisjointSet(DisjointSet *set) {
  46. free(set->parent);
  47. free(set->rank);
  48. }
  49. int main() {
  50. // 示例用法
  51. int size = 10; // 假设有10个元素
  52. DisjointSet set;
  53. initDisjointSet(&set, size);
  54. // 进行一些合并操作
  55. unionSets(&set, 0, 1);
  56. unionSets(&set, 2, 3);
  57. unionSets(&set, 4, 5);
  58. unionSets(&set, 6, 7);
  59. unionSets(&set, 1, 2);
  60. unionSets(&set, 5, 6);
  61. unionSets(&set, 3, 7);
  62. // 查找操作
  63. printf("Element 0 is in set with representative: %d\n", find(&set, 0));
  64. printf("Element 4 is in set with representative: %d\n", find(&set, 4));
  65. // 释放内存
  66. freeDisjointSet(&set);
  67. return 0;
  68. }

这是一个简单的并查集的实现,你可以根据实际需要进行扩展和优化。并查集的主要思想是通过合并集合的操作,将元素划分到不同的集合中,同时通过查找操作找到元素所在的集合。这种数据结构在解决一些图论和连通性的问题中非常有用。

二 时空复杂度

并查集的主要操作是查找(Find)合并(Union)。下面是对这两个操作的时空复杂度分析:

A.查找操作(Find):

时间复杂度: Amortized O(α(n)),其中 α(n) 是 Ackermann 函数的反函数,增长非常缓慢,可以近似看作是常数时间。在实际应用中,查找操作几乎可以看作是常数时间。


空间复杂度: O(n),其中 n 是并查集的大小。这是由于需要存储每个元素的父节点。


B.合并操作(Union):

时间复杂度: Amortized O(α(n)),其中 α(n) 是 Ackermann 函数的反函数,增长非常缓慢,可以近似看作是常数时间。合并操作的复杂度主要由查找操作决定。


空间复杂度: O(n),同样是由于需要存储每个元素的父节点。

三 优缺点

A.优点:

高效的合并操作: 并查集的合并操作具有较好的平均时间复杂度。通过使用路径压缩和秩优化等技术,可以保持较低的合并代价。

高效的查找操作: 并查集的查找操作(Find)在实际应用中通常是近似常数时间,尤其是在使用路径压缩的情况下。

简单直观: 并查集的实现相对简单,易于理解和实现。这使得它成为解决一些连通性问题的常用选择。

空间效率: 并查集在空间上的占用主要是存储每个元素的父节点和秩等信息,相对来说是比较节省空间的。

B.缺点:

不适用于所有问题: 并查集主要用于处理集合的合并和查找操作,但并不适用于所有类型的问题。对于其他类型的问题,可能有更适合的数据结构。

无法回溯修改历史操作: 一旦执行了合并操作,就很难回溯修改历史的操作。这使得并查集在一些需要撤销或修改历史状态的场景中不够灵活。

可能存在树不平衡的问题: 尽管使用了路径压缩和秩优化等策略,但在实际操作中,仍可能导致并查集中树的不平衡,使得部分操作的代价较高。

C.总结:

总体来说,并查集在处理特定类型的问题时非常高效,但在某些场景下可能不如其他数据结构适用。在选择数据结构时,需要根据具体问题的特点和要求进行权衡。

四 现实中的应用

图论中的连通性问题: 并查集常被用于解决图的连通性问题,如判断图中是否存在环,或者确定两个节点是否连通。在网络设计、社交网络分析等领域,这种连通性问题经常需要解决。

图像分割: 在计算机视觉中,图像分割是一个重要的问题。并查集可以用于将图像中的像素分组,形成一些区域,使得同一区域内的像素属于同一集合。

操作系统中的文件系统管理: 文件系统中的文件和目录之间存在关系,而这些关系可以使用并查集来管理。当文件或目录被移动或删除时,使用并查集可以有效地更新这些关系。

网络连接状态的管理: 在网络通信中,可以使用并查集来管理设备之间的连接状态。这对于网络设计和维护具有实际意义,例如在通信网络中检测环路。

最小生成树算法: 在图论中,最小生成树算法(如Kruskal算法)通常使用并查集来判断边的两个端点是否在同一连通分量中,以避免形成环路。

社交网络中的关系管理: 在社交网络中,人与人之间的关系可以使用并查集来管理。当两个人建立关系(如好友关系)时,可以将它们合并到同一个集合中。

数据库查询优化: 在数据库中,关联查询可以通过并查集来优化。通过维护表之间的关系,可以更高效地执行一些查询操作。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/836039
推荐阅读
相关标签
  

闽ICP备14008679号