二叉搜索树 & 平衡树学习笔记

注意,这是一篇学习笔记。

二叉搜索树(BST)

定义

  1. 空树是二叉搜索树
  2. 若二叉搜索树的左子树非空,左子树内每个点的权值均 小于 二叉搜索树根节点的权值
  3. 若二叉搜索树的右子树非空,右子树内每个点的权值均 大于 二叉搜索树根节点的权值
  4. 二叉搜索树的左右子树为二叉搜索树

二叉搜索树中每个节点有一个权值 \(\mathit{val}\),一个重复数量 \(\mathit{cnt}\)。还需要额外记录子树大小 \(\mathit{siz}\)

性质

由定义可得一颗二叉搜索树的中序遍历的节点序列的权值单调递增。可以此完成 \(O(n)\) 的遍历。

操作

设树高为 \(h\),则以下操作时间复杂度均为 \(O(h)\)

极值

由性质得最小值在二叉搜索树最小值在最左边的节点,最大值则在最右边的节点。

搜索值

当在二叉搜索树中搜索 \(x\) 时,对于当前根节点 \(r\)

  • \(r\) 为空,返回 false
  • \(r.\mathit{val}=x\),返回 true
  • \(x<r.\mathit{val}\),在左子树中递归查找
  • \(r.\mathit{val}<x\),在右子树中递归查找

插入值

类似于搜索值:

  • \(r\) 为空,返回一个新节点
  • \(r.\mathit{val}=x\)\(r.\mathit{cnt}\gets r.\mathit{cnt}+1\)
  • \(x<r.\mathit{val}\),在左子树中递归
  • \(r.\mathit{val}<x\),在右子树中递归

删除值

依然类似,但稍有不同:

  • \(r\) 为空,则没有这个值,直接返回
  • \(r.\mathit{val}=x\)\(r.\mathit{cnt}\gets r.\mathit{cnt}-1\),此时若 \(r.\mathit{cnt}=0\)
    • \(r\) 为叶子,直接删除即可
    • \(r\) 只有一个儿子,让此儿子代替 \(r\) 即可
    • \(r\) 有两个儿子,让左子树中的最大值\右子树的最小值代替 \(r\) 即可
  • \(x<r.\mathit{val}\),在左子树中递归
  • \(r.\mathit{val}<x\),在右子树中递归

值求排名

一个值的排名:升序排序后第一个相同元素前面的元素个数 \(+1\)

对于

1 1 4 5 1 4

排序后

1 1 1 4 4 5

其中 \(4\) 的排名为 \(4\)

实现:

搜索过程中若往右子树走,则加上左子树的 \(\mathit{siz}\),最后再加上到达的节点的左子树 \(\mathit{siz}\)

显然左子树中的数都比 \(x\) 小。

排名求值

在一棵子树中,根节点的排名取决于其左子树的大小。

对于根节点 \(r\),求 该子树中 的排名为 \(k\) 的值,

  • \(k\le r.ls.\mathit{siz}\),则所求在左子树中,递归查询左子树的排名 \(k\)
  • \(r.ls.\mathit{siz}+1\le k\le r.ls.\mathit{siz}+r.\mathit{cnt}\),则返回 \(r.\mathit{val}\)
  • \(r.ls.\mathit{siz}+r.\mathit{cnt}<k\),则递归查询右子树的排名 \(k-(r.ls.\mathit{siz}+r.\mathit{cnt})\)

平衡树

使用搜索树的目的之一是缩短插入、删除、修改和查找(插入、删除、修改都包括查找操作)节点的时间。

但有一个小小的问题:当二叉搜索树退化为链表时,\(h=n\),复杂度随之退化为 \(O(n)\)

所以我们需要使整棵二叉搜索树平衡。

树堆(Treap)

本节为旋转 Treap。

节点

每个节点有两个值:权值 \(v\) 和优先级 \(p\)。其中 \(p\) 是随机给出的。

首先要明确的是,对于一个排序过的序列,对它建立 BST,该 BST 有很多形态。许多形态是我们不想要的,因为它们太“瘦长”了。

有了 \(p\),我们的 Treap 不仅要满足 BST 的性质,还要满足堆(Heap)的性质,即子节点的 \(p\) 大(小于)父节点的 \(p\)。这也正是 Treap 名字的由来:Treap=Tree+Heap。

通过随机化,我们成功地让 Treap 保持了弱平衡。

旋转

旋转操作分为左旋和右旋。

直观理解:

对于左旋节点 \(x\),若 \(x\) 右儿子为 \(y\)

  • \(x\) 左儿子,\(y\) 的右儿子不变;
  • \(y\) 作为新根节点,\(x\) 的右儿子改为 \(y\) 的左儿子,\(y\) 的左儿子改为 \(x\)

右旋同理。

posted @ 2024-01-13 14:47  Po7ed  阅读(3)  评论(0编辑  收藏  举报