算法学习笔记(21): 平衡树(二)

这篇具有很好参考价值的文章主要介绍了算法学习笔记(21): 平衡树(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

平衡树(二)

平衡树(一)链接:算法学习笔记(18): 平衡树(一) - jeefy - 博客园

本文中将讲述一下内容:

  • 可持久化Treap

  • 基于Trie 平衡树(后文称之为 BSTrie

  • BSTrie的可持久化

可持久化Treap

可持久化Treap基于FHQ-Treap。其实不难发现,FHQ-Treap在分裂和合并时在每一层只对一个结点产生影响。于是我们可以大胆的可持久化此结构,且保证复杂度为 \(O(\log n)\)

我们以此图为例。我们只需要复制下被影响的结点,基于原树获得一条新链:

红色节点是新产生的节点(可能实际上产生的顺序不一样)

其中 (8, 11) 作为新右树的根,(7, 8) 作为新左树的根

也就是说,我们经过一个结点复制一次即可。

inline void splitVal(int p, int val, int &x, int &y, bool simple = true) {
    if (!p) return (void)(x = y = 0);
    int np = simple ? p : clone(p);
    if (val(p) <= val)
        x = np, splitVal(rp(p), val, rp(x), y, simple), update(x);
    else
        y = np, splitVal(lp(p), val, x, lp(y), simple), update(y);
}

simple就是标志是否需要可持久化……特别简单

其实到这里就已经讲完了可持久化Treap了……因为其他绝大部分操作只需要对于分裂时持久化,在合并时并不需要持久化。

例如删除操作:

inline int insert(int root, int val, bool simple = false) {
    int x(0), y(0), p(++usage);
    nodes[p].init(val);
    splitVal(root, val, x, y, simple);
    return merge(merge(x, p), y);
}

这也请读者自行思考为什么不需要合并时可持久化。

基于Trie的 类 平衡树(BSTrie)

这里基于的Trie指的是 \(01Trie\),考虑其实每一个数都可以被拆分为二进制,于是有了此做法。

说实话,代码无比之简短,并且十分迅速,除了空间复杂度较大之外,令我不禁想要抛弃WBLT……

后记:空间复杂度……真的很大,很多普通平衡树能过的空间,Trie真不一定能过

我们首先只考虑正数的情况。如果我们把每一个数都扩展成同一个位长,从高位向低位保存成一棵树。我们从左到右(认为0在左,而1在右)观察其叶节点所对应的值(类似于Leafy Tree),可以知道是单调递增的,于是我们可以轻易的将之进行魔改,从而做到普通平衡树所能做到的事。


template<int N = 100000>
class BSTrie {
private:
    int siz[N << 5];
    int ch[N << 5][2];
    int usage;
    #define newNode() ({ \
        ++usage; \
        siz[usage] = ch[usage][0] = ch[usage][1] = 0; \
        usage; \
    })
}

这是这一颗树需要用到的内容。其实从这里就应该可以知道,其空间复杂度为 \(O(n \log C)\) 其中 \(C\) 表示值域大小,一般为 \(32\)。这与其他空间为 \(O(n)\) 的平衡树相比远远不如……

插入

首先看代码:

void insert(int x) {
    int p = 1; 
    for (int i = BS; ~i; --i) {
        int bt = bit(x, i), &np = ch[p][bt];
        if (!np) np = newNode();
        p = np, ++siz[p];
    }
}

写法有些许迷惑,见谅

其中BS指的是 \(\lceil \log C \rceil\)

由于我们需要用到子树的大小以方便 \(rank, kth\) 操作,所以对于路径上 ++siz[p]

不就是普通的 Trie 插入操作吗?不讲了。

删除

void remove(int x) {
    int p = 1;
    for (int i = BS; ~i; --i) {
        int np = ch[p][bit(x, i)];
        if (!np) return;
        p = np;
    }

    p = 1;
    for (int i = BS; ~i; --i) {
        p = ch[p][bit(x, i)], --siz[p];
    }
}

这里需要注意的是需要两遍向下,以防止 x 并不存在的情况。

与普通的 Trie 删除操作类似,想必代码也十分易懂。

查询排名

在普通平衡树内查询排名怎么查,这里就怎么查:

  • 进入右子节点,则累加左子树的大小

  • 进入左子节点,则不累加

  • 没有子节点,直接返回当前结果

int rank(int x, bool within = false) {
    int p = 1;
    int rk = 0;
    if (x >= 0) rk += siz[1];
    for (int i = BS; ~i; --i) {
        int bt = bit(x, i), np = ch[p][bt];
        if (bt) rk += siz[ch[p][0]];
        if (!np) return rk;
        p = np;
    }

    return within ? rk + siz[p] : rk;
}

这里对于加入了 within 参数,用于提示是否需要包含 x 出现的次数。

为什么在第8行直接返回是正确的?简单来说就是空子树不会对结果造成影响。具体一点请读者自行思考。

查询第k大

呃,令 x 为当前结果:

  • 若进入左子树,则令 x = x << 1

  • 否则令 x = (x << 1) | 1(打括号是为了方便理解)

如果保证树内存在至少 \(k\) 个数,则一定可以找到正确答案,且不会进入空子树。

但是没有这么多个数……则结果不可预测

int kth(int k) {
    int p = 1;
    int x = 0;
    for (int i = BS; ~i; --i) {
        if (k <= siz[lc(p)]) p = lc(p), x <<= 1;
        else k -= siz[lc(p)], p = rc(p), x = (x << 1) | 1;
    }
    return x;
}

于是,你可以在100行内写出一个优秀的平衡树了……


现在考虑有复数的情况。有两种解决方法:

  • 依据符号位,建两棵树。根据补码的知识,对于有符号类型的整数,其对应的无符号整型数值越大,其值越大。所以负数也可以利用同样的代码处理。

    而改变方法也很简单,将语句 int p = 1 改为 int p = x < 0 ? 1 : 2(标号随意)即可。
    只是在 kth 时,需要有:int x = k <= siz[1] ? (1 << (32 - BS)) - 1 : 0;

    rank 前要多加一句:if (x >= 0) rk += siz[1];

    其他的都没大区别。

  • 第二种方案相对简单,把所有数都加上一个 offset,保证为正整数即可……(这种方法很简答,而且可持久化时也更简单)

于是我们优先采用第二种方法(尤其是需要可持久化的时候)。


可持久化BSTrie

可持久化 Trie 会吧……OK,下课!

还是提一下可持久化的思想:

把每一个经过的结点复制出来即可……类比可持久化Treap的操作文章来源地址https://www.toymoban.com/news/detail-441923.html

到了这里,关于算法学习笔记(21): 平衡树(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构和算法学习记录——平衡二叉树(基本介绍、平衡因子、平衡二叉树的定义、平衡二叉树的高度)

    目录 基本介绍 平衡因子 平衡二叉树  平衡二叉树的高度  什么是平衡二叉树? 以一个例子来解释一下: 搜索树结点按不同的插入次序,将会导致不同的深度和平均查找长度ASL   在二叉搜索树中查找一个元素:  (a)要找到Jan,需要查找一次;要找到Feb,需要查找两次;

    2023年04月26日
    浏览(67)
  • 学习高级数据结构:探索平衡树与图的高级算法

    🎉欢迎来到数据结构学习专栏~学习高级数据结构:探索平衡树与图的高级算法 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:数据结构学习 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技

    2024年02月09日
    浏览(46)
  • 论文笔记:基于概念漂移的在线类非平衡学习系统研究

    论文:A Systematic Study of Online Class Imbalance Learning With Concept Drift 发表:2018年发表在TNNLS上 源代码:? 作为一个新兴的研究课题,在线类非平衡学习往往结合了类非平衡和概念漂移的挑战。它处理具有非常倾斜的类分布的数据流,其中可能发生概念漂移。它最近受到越来越多的

    2024年02月11日
    浏览(78)
  • 学习笔记21 list

    有两种不同的方法来实现List接口。 ArrayList 类使用基于连续内存分配的实现,而 LinkedList 实现基于 linked allocation 。 list接口提供了一些方法: 1.构造方法 这两个类有相似的构造方法: 使用第三种构造方法可以将list转为arraylist: 用for循环将数组转为linkedlist:  注意, java中的

    2024年02月15日
    浏览(33)
  • Docker学习笔记21

    案例三:使用容器运行一个wordpress应用:         语言开发环境(PHP)         数据库 第一步:创建一个工程目录: 第二步:创建一个docker-compose.yaml文件: 我们再理解下depends_on: 这个是依赖的意思。 --links:容器的互联,是一种让多个容器中的应用进行快速交互的方式,

    2024年02月13日
    浏览(49)
  • 【❤️算法笔记❤️】-每日一刷-21、合并两个有序链表

    简单 相关标签 相关企业 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 示例 2: 示例 3: 提示: 两个链表的节点数目范围是 [0, 50] -100 = Node.val = 100 l1 和 l2 均按 非递减顺序 排列 拉拉链法 两个链表就相当于

    2024年03月12日
    浏览(84)
  • LiangGaRy-学习笔记-Day21

    1、LVM介绍 1.1、LVM是什么 对于生产环境下的服务器来说,如果存储数据的分区磁盘空间不足,应该如何处理? 添加一块硬盘–可以满足需要 再添加一块硬盘也可以满足需求; 问题就是拷贝的速度慢; 这里就引入一个技术:LVM在线动态扩容 raid:支持冗余和安全–支持速度

    2024年02月08日
    浏览(42)
  • 企业架构LNMP学习笔记21

    URL重写: ngx_http_rewrite_module 模块用于使用 PCRE正则表达式更改请求URI ,返回重定向,以及有条件地选择配置。 return 该指令用于结束结束规则的执行并返回状态码给客户端。 403 Forbidden.服务器已经理解请求,但是拒绝执行它 404 Not Found.请求失败, 请求所希望得到的资源未在服务

    2024年02月09日
    浏览(40)
  • Java学习笔记21——常用API

    在 java.lang 下,使用不需要导包 被 final 修饰,是最终类,没有子类 执行基本数字运算的方法 没有构造方法,直接用类名访问(被static修饰 )。 Math的常用方法 在 java.lang 下,使用不需要导包 被 final 修饰,是最终类,没有子类 System类包含几个有用的类字段和方法。它不能被

    2024年02月07日
    浏览(47)
  • SpringMVC《学习笔记(21版尚硅谷)》

    1、什么是MVC MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分 M:Model,模型层,指工程中的JavaBean,作用是处理数据 JavaBean分为两类: 一类称为实体类Bean:专门存储业务数据的,如 Student、User 等 一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业

    2024年02月08日
    浏览(85)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包