《算法导论》笔记 第21章 21.3 不相交集合森林

【笔记】


用有根树来表示集合,树中的每个结点都包含集合的一个成员,每棵树表示一个集合。

每个成员仅指向其父结点。每棵树的根包含了代表,并且是它自己的父结点。

MAKE-SET 创建一棵仅包含一个结点的树。

FIND-SET 找到树根。

UNION 使得一棵树根指向另一棵。


改进运行时间的启发式策略

按秩合并:使得包含较少结点的树的根指向包含较多结点的树的根。

路径压缩:使查找路径上的每个结点都直接指向根结点。路径压缩并不改变结点的秩。


代码

int p[maxn];
int rank[maxn];
void makeSet(int x) {
    p[x] = x;
    rank[x] = 0;
}
void link(int x, int y) {
    if (rank[x] > rank[y]) { p[y] = x; }
    else {
        p[x] = y;
        if (rank[x] == rank[y]) { rank[y] += 1; }
    }
}
int findSet(int x) {
    if (x != p[x]) { p[x] = findSet(p[x]); }
    return p[x];
}
void unionSet(int x, int y) {
    link(findSet(x), findSet(y));
}
void setInit(int n) {
    for (int i=0;i<=n;i++) makeSet(i);
}

启发式策略对运行时间的影响

按秩合并 O(mlgn)

路径压缩 Θ(n+f·(1+log_{2+f/n}n))

同时 O(mα(n)),其中α(n)是一个增长及其缓慢的函数。



【练习】


21.3-1 按秩合并和路径压缩启发式的不相交集合森林重做里练习21.2-2。

    setInit(16);
    for (int i=1;i<=15;i+=2) unionSet(i,i+1);
    for (int i=1;i<=13;i+=4) unionSet(i,i+2);
    unionSet(1,5);
    unionSet(11,13);
    unionSet(1,10);
    cout<
16

16


21.3-2 写出FIND-SET路径压缩的非递归版本。

int findSet2(int x) {
    int y = x, z;
    while (x != p[x]) { x = p[x]; }
    while (y != p[y]) {
        z = y;
        y = p[y];
        p[z] = x;
    }
    return x;
}


21.3-3 请给出一个包含m个MAKE-SET、UNION和FIND-SET操作的序列(其中n个是MAKE-SET操作),使得采用按秩合并时,这一操作序列的代价为Ω(mlgn)。



*21.3-4 证明:在采用了按秩合并和路径压缩时,任意一个包含m个MAKE-SET、FIND-SET和LINK操作的序列需要O(m)的时间。如果仅用启发式呢。




你可能感兴趣的:(算法导论)