本次笔记内容:
5.3.1 集合的表示及查找
5.3.2 集合的并运算

集合的表示

  • 集合的运算包括:交、并、补、差、判定一个元素是否属于某一集合。

并查集

  • 并查集:集合并、查某元素属于什么集合。
  • 并查集问题的现实中例子:
    有10台电脑{1,2,3,…,9,10},已知下列电脑之间已经实现了连接:
    1和2、2和4、3和5、4和7、5和8、6和9、6和10,问:2和7之间,5和9之间是否是连通的?

上例解决思路:

  1. 将10台电脑看成10个集合{1},{2},{3},…,{9},{10};
  2. 已知一种连接“x和y”,就将x和y对应的集合合并;
  3. 查询“x和y是否是连通的”就是判别x和y是否属于同一集合。

并查集问题中的存储实现

  • 可以用树结构表示集合,树的每个结点代表一个集合元素。

【数据结构笔记17】集合的表示、双亲表示法、并查集、集合的并运算_并查集

如上,使用双亲表示法。双亲的下标即代表集合。

【数据结构笔记17】集合的表示、双亲表示法、并查集、集合的并运算_结点_02

如上图,2的父结点为1,1的下标为0,因此Parent为1;对于没有父结点的根结点,其Parent为-1。

typedef struct
{
    ElementType Data;
    int Parent;
} SetType;

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

集合的并运算

  • 分别找到X1和X2两个元素所在集合树的根节点;
  • 如果他们不同根,则将其中一个根结点的父结点指针设置成另一个根结点的数组下标。

直接实现的方法

void Union(SetType S[], ElementType X1, ElementType X2)
{
    int Root1, Root2;
    Root1 = Find(S, X1);
    Root2 = Find(S, X2);
    if (Root1 != Root2)
        S[Root2].Parent = Root1;
}

Union函数更好的思想

上述实现可能造成树越来越高,降低查找效率。因此,为了改善合并以后的查找性能,可以采用小的集合合并到相对大的集合中的办法。

【数据结构笔记17】集合的表示、双亲表示法、并查集、集合的并运算_双亲表示法_03

使用根结点表示集合元素数量即可。