注:由于这东西既满足树的性质,又满足堆的性质,所以可能两个概念的名词都会使用。
左偏树,是一种可并堆。可以实现两个堆的 合并。(本文以大根堆为例)
形态上来讲是一颗二叉树。
性质上定义一个点的 值为当前点距离最近的叶子结点的距离,根据它的名字就可以知道,左儿子的 值应该大于右儿子。同时作为一个堆,他应该满足父节点权值大于子节点的性质。
写法上有点像 和并查集的结合体,因为要进行合并操作和路径压缩。(可能我技能加点顺序不太对?)
具体实现:
可并堆要维护的信息:
-
分别表示一个点的左儿子和右儿子。
-
表示一个点所在堆的堆顶。
也就是说,一个点的 一定是它的直接儿子,而他的 不一定是它的父亲。
-
值含义如上文。
-
表示一个点的权值。
要实现的操作:
-
操作,将一个独立的值建成一个堆,并进行一些初始化操作。
-
合并两个点所在的堆。其实就是 合并操作的阉割版。
默认两个堆中较大的根节点为当前新堆的根节点,然后递归合并右子树和另一个堆。检查左右子树 值进行交换来满足左偏性质。
注意将左右子树的 值设为新的根节点,以及更新当前根节点的 值。
-
取出当前点的堆顶节点,同时进行路径压缩
-
弹出当前点的堆顶节点。
直接将堆顶节点的左右儿子的 值设为自身,将左右子树合并,再将之前根节点的左右儿子设为 0。
同时,由于进行过路径压缩操作,所以要将之前的堆顶的 值设为合并后的新堆的根节点。这样既满足了从堆中删除了堆顶,也不会使子树节点迷失。
总结:注意更新 ,同时,该更新左右儿子的时候得更新,否则后面可能会引起冲突。
代码实现:
- 维护的信息
1 | // 左偏树 学习笔记 |
- 操作:
1 | // 左偏树 学习笔记 |
有的题要求按照编号进行操作,也可以改成这样:
1 | // 左偏树 学习笔记 |
- 操作:
递归部分代码实现:
1 | // 左偏树 学习笔记 |
非递归部分代码实现:
1 | // 左偏树 学习笔记 |
- 操作:
1 | // 左偏树 学习笔记 |
- 操作:
1 | // 左偏树 学习笔记 |
代码实现:
1 | // 左偏树 学习笔记 |
本文作者:CloudySky
写作时间: 2022-01-28
最后更新时间: 2022-01-28
遵循协议: BY-NC-SA