博客
关于我
【用梨泰院class中的财阀世家带你洞悉替罪羊树】Scapegoat Tree原理,模板,例题
阅读量:294 次
发布时间:2019-03-03

本文共 2974 字,大约阅读时间需要 9 分钟。

重新理解替罪羊树

前言

我最近在学习数据结构时,逐渐对平衡树的概念产生了浓厚兴趣。通过对比和实践,我逐渐理解了替罪羊树的工作原理。这让我联想到韩剧中的财阀世家,复杂的权力斗争和权力更迭让我对替罪羊树的“拍扁重构”机制有了更深入的理解。

替罪羊树的概念

替罪羊树是一种基于“拍扁重构”的二叉平衡树,通过打乱子树的结构来维护平衡性。与旋转平衡树相比,替罪羊树更注重通过稳固的“亲情”来维持树的平衡。

核心原理

替罪羊树的平衡机制依赖于一个叫做“平衡因子”的概念。这个因子用于判断树的子树是否需要重构。具体来说,当左或右子树的节点数占比超过平衡因子的限制时,整个子树就会被拍扁重构。

平衡因子的选择

平衡因子的取值范围通常在0.5到1之间。常见的选择是0.7左右。这一参数值的选择需要权衡插入和查询的效率。较大的α值会减少重构次数,提高插入效率,但可能导致查询效率下降。

替罪羊树的优点与缺点

优点

  • 代码简洁:替罪羊树的代码逻辑相对简单,易于调试。
  • 性能较好:在大多数操作下,替罪羊树的性能表现优于一些旋转平衡树。
  • 易于理解:其“拍扁重构”机制直观地类似于对家族权力结构的调整。
  • 缺点

  • 区间操作受限:替罪羊树不支持区间操作,这在某些应用场景下是个限制。
  • 重构频率高:在某些负载下,频繁的重构操作可能带来性能瓶颈。
  • 替罪羊树的实现

    数据结构定义

    struct Scapegoat {    bool exist;    int son[2], val, alive, total;};int idx1, idx2, flag, root, Size;int cur[MAXN], memory[MAXN];

    重构函数

    void flat(int rt) {    if (!rt) return;    flat(t[rt].son[0]);    if (t[rt].exist) cur[++idx1] = rt;    else memory[++idx2] = rt;    flat(t[rt].son[1]);}void build(int l, int r, int &rt) {    int mid = (l + r) >> 1;    rt = cur[mid];    if (l == r) {        t[rt].son[0] = t[rt].son[1] = 0;        t[rt].alive = t[rt].total = 1;        return;    }    if (l < mid) build(l, mid - 1, t[rt].son[0]);    else t[rt].son[0] = 0;    build(mid + 1, r, t[rt].son[1]);    t[rt].total = t[t[rt].son[0]].total + t[t[rt].son[1]].total + 1;    t[rt].alive = t[t[rt].son[0]].alive + t[t[rt].son[1]].alive + 1;}void rebuild(int &rt) {    idx1 = 0;    flat(rt);    if (idx1) build(1, idx1, rt);    else rt = 0;}

    插入函数

    void insert(int &rt, int val) {    if (!rt) {        rt = memory[idx2--];        t[rt].val = val;        t[rt].exist = t[rt].alive = t[rt].total = 1;        t[rt].son[0] = t[rt].son[1] = 0;        return;    }    t[rt].alive++;    t[rt].total++;    if (val <= t[rt].val) insert(t[rt].son[0], val);    else insert(t[rt].son[1], val);    if (Bad(rt)) rebuild(rt);}

    删除操作

    void Delete_rnk(int &rt, int rnk) {    if (t[rt].exist && t[t[rt].son[0]].alive + 1 == rnk) {        t[rt].exist = 0;        t[rt].alive--;        return;    }    t[rt].alive--;    if (rnk <= t[t[rt].son[0]].alive + t[rt].exist)        Delete_rnk(t[rt].son[0], rnk);    else        Delete_rnk(t[rt].son[1], rnk - t[t[rt].son[0]].alive - t[rt].exist);}void Delete_val(int val) {    Delete_rnk(root, FindRank(val));    if ((double)t[root].total * alpha > t[root].alive)        rebuild(root);}

    查找功能

    int FindRank(int k) {    int rt = root, ans = 1;    while (rt) {        if (k <= t[rt].val) rt = t[rt].son[0];        else {            ans += t[t[rt].son[0]].alive + t[rt].exist;            rt = t[rt].son[1];        }    }    return ans;}int FindKth(int k) {    int rt = root;    while (rt) {        if (t[rt].exist && t[t[rt].son[0]].alive + 1 == k)            return t[rt].val;        else if (k <= t[t[rt].son[0]].alive)            rt = t[rt].son[0];        else {            k -= (t[t[rt].son[0]].alive + t[rt].exist);            rt = t[rt].son[1];        }    }    return -1;}

    总结

    替罪羊树以其独特的“拍扁重构”机制,为平衡树提供了一种直观的理解方式。通过类比现实中的财阀世家权力斗争,我们可以更直观地感受到替罪羊树的工作原理。虽然其在某些场景下存在局限性,但其代码简洁、逻辑清晰,使其成为学习平衡树的一种不错的选择。

    转载地址:http://pxil.baihongyu.com/

    你可能感兴趣的文章
    Python+统计学 | 探索常用的数据分析统计分布
    查看>>
    python, selenium中用于切换帧的函数
    查看>>
    python函数
    查看>>
    python----线程、进程、协程的区别及多线程详解
    查看>>
    python---5
    查看>>
    python---使用celery分布式系统异步发送短信(云通讯)来验证登录
    查看>>
    python--003--百分号字符串拼接、format
    查看>>
    Python--10、线程
    查看>>
    Python--Redis实战:第四章:数据安全与性能保障:第4节:复制
    查看>>
    python--基本代码规范
    查看>>
    Python--抽象类接口类
    查看>>
    PYTHON--欧拉习题二
    查看>>
    python--高级应用总结
    查看>>
    python-520表白代码,我看谁说程序员不懂浪漫,送你几套表白代码,一步到位
    查看>>
    Python-Asyncio TypeError:无法在‘;等待‘;表达式中使用对象DICT
    查看>>
    Python-AttributeError:‘;dict&39;对象没有属性‘;序列‘;
    查看>>
    Python-ldap:是否可以在不显式写入密码的情况下进行绑定?
    查看>>
    python出现 unknown encoding: idna 的处理方法
    查看>>
    Python出现 RuntimeError: dictionary changed size during iteration 的解决方法
    查看>>
    Python-numpy(2)数组的操作
    查看>>