zoukankan      html  css  js  c++  java
  • 集合的查、并运算,即简化版运算方法,按秩归并,压缩路径

    集合的表示:
    1.集合运算:交、并、补、差,判定里两个元素是否属于某一个集合
    2.并查集:集合并、查某元素属于什么集合
    3.并查集可以用树结构表示,树的每个结点表示一个集合元素
    双亲表示法:(孩子指向双亲)
    这个树结构采用数组存储形式:
    数组每个元素的类型描述为:

    1 typedef struct {
    2     ElementType Data;
    3     int Parent;
    4 }SetType; 

    集合运算(下面的完整代码中用简化版的查,并运算,体会二者差别)

    (1)查找某个元素所在集合(用根节点表示)

    1 int Find(SetType s[], ElementType X)
    2 {        //在数组s中查找值为x的元素的所属集合
    3         //MaxSize是全局变量,为数组s的最大长度
    4     int i;
    5     for(i = 0; i < MaxSize && S[i].Data != X; i++);
    6     if(i >= MaxSize) return -1;            //未找到x,返回-1
    7     for(; s[i].parent >= 0; i = s[i].parent);
    8     return i;            //找到x所属集合,返回树根节点在数组s中的下标
    9 }


    (2)集合并运算
    分别找到x1, x2两个元素所在集合树的根节点
    如果他们不同根,则将其中一个根节点的父节点设置成另一个根节点的数组下标

    1 void Union(SetType S[], ElementType x1, ElementType x2 )
    2 {
    3     int Root1, Root2;
    4     Root1 = Find(S, x1);
    5     Root2 = Find(S, x2);
    6     if(Root1 != Root2)
    7         S[Root2].parent = Root1;
    8 }

    为了改善合并以后的查找性能,可以采用小的集合合并到相对大的集合
    用根节点的parent的绝对值来表示集合的结点个数

    简化版查、并运算完整代码

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 #define MaxSize 15
     5 typedef int ElementType;    //默认元素用非负数表示
     6 typedef int SetName;        //默认用根节点的下标表示集合名称
     7 typedef ElementType SetType[MaxSize];
     8 
     9 void Initialization(SetType S, int n)
    10 {
    11     for (int i = 0; i < n; i++)
    12         S[i] = -1;
    13 }
    14 
    15 
    16 SetName Find(SetType S, ElementType X)
    17 {
    18     //默认集合元素全部初始化为-1
    19     for (; S[X] >= 0; X = S[X]);
    20     return X;
    21 }
    22 
    23 
    24 void Union(SetType S, SetName root1, SetName root2)
    25 {
    26     S[root2] = root1;    
    27 }
    28 
    29 void Input_connection(SetType S)
    30 {
    31     ElementType u, v;
    32     SetName root1, root2;
    33     scanf_s("%d %d", &u, &v);
    34     root1 = Find(S, u - 1);
    35     root2 = Find(S, v - 1);
    36     if (root1 != root2)
    37         Union(S, root1, root2);
    38 }
    39 
    40 void Check_connection(SetType S)
    41 {
    42     ElementType u, v;
    43     SetName root1, root2;
    44     scanf_s("%d %d", &u, &v);
    45     root1 = Find(S, u - 1);
    46     root2 = Find(S, v - 1);
    47     if (root1 == root2)
    48         printf("yes
    ");
    49     else
    50         printf("no
    ");
    51 }
    52 
    53 //检查是否所有结点都连通了
    54 void Check_network(SetType S, int n)
    55 {
    56     int i, counter = 0;
    57     for (i = 0; i < n; i++)
    58     if (S[i] < 0) counter++;
    59     if (counter == 1)
    60         printf("The net work is connected.
    ");
    61     else
    62         printf("There are %d components.
    ", counter);
    63 }
    64 
    65 int main()
    66 {
    67     SetType S;
    68     int n;
    69     char in;
    70     scanf_s("%d", &n);
    71     Initialization(S, n);
    72     do{
    73 
    74         scanf_s("%c", &in);
    75         switch (in)
    76         {
    77         case 'I':
    78             Input_connection(S);
    79             break;
    80         case 'C':
    81             Check_connection(S);
    82             break;
    83         case 'S':
    84             Check_network(S, n); 
    85             break;
    86         }
    87     } while (in != 'S');
    88     return 0;
    89 }

    按秩归并(进一步优化程序)

    有两种方式

    (一)

     1 //按秩归并
     2 void Union(SetType S, SetName root1, SetName root2)
     3 {
     4     /*if (S[root1] < S[root2])        //S[root]中存树的高度
     5     S[root2] = root1;
     6     else
     7     {
     8     if (S[root1] == S[root2])
     9     S[root1]--;
    10     S[root1] = root2;
    11     }*/
    12 }

    (二)

     1 void Union(SetType S, SetName root1, SetName root2)
     2 {
     3 
     4     if (S[root2] < S[root1])        //S[root]中存树的结点个数
     5     {
     6         S[root2] += S[root1];
     7         S[root1] = root2;
     8     }
     9     else
    10     {
    11         S[root1] += S[root2];
    12         S[root2] = root1;
    13     }
    14 
    15 
    16 }

    路径压缩(极大的减少运行时间)

    1 //路径压缩    降低了输的高度,使查找过程中访问过的结点都直接指向根节点
    2 SetName Find(SetType S, ElementType X)
    3 {
    4     if (S[X] < 0)
    5         return X;
    6     else
    7         return S[X] = Find(S, S[X]);    //先找到根,把根变成X的父节点,在返回根
    8 }
  • 相关阅读:
    Dev Express WPF GridControl 数据导出到Excel
    WPF DockLayoutManager布局后的布局重置
    几个平台视频,音频下载(批量下载)到本地的方式
    CSS 清除内外边距
    盒子模型外边距合并--塌陷问题
    log4net 配置数据库连接
    Common.Logging+log4net搭建项目日志框架
    VS2019 找不到资产文件 “xxxxobjproject.assets.json”运行NuGet包还原以生成此文件
    javascript的数组之slice()
    javascript的数组之includes()
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/9531527.html
Copyright © 2011-2022 走看看