平衡树-Splaytree
前置知识:二叉搜索树。
参考资料
https://blog.csdn.net/ModestCoder_/article/details/90139481
https://baike.baidu.com/item/%E5%B9%B3%E8%A1%A1%E6%A0%91/7641279?fr=aladdin
大纲
平衡树-Splaytree
平衡树
平衡树 \color{black}\texttt{平衡树} 平衡树
平衡树简介 \color{black}\texttt{平衡树简介} 平衡树简介
平衡树中最简单的就是 Splaytree \texttt{Splaytree} Splaytree(中文名是伸展树)了。平衡树是一种二叉搜索树,首先要知道什么是二叉搜索树:
二叉搜索树是一棵二叉树。这棵二叉树把值 k e y key key 放在每个节点上,并且左儿子权值 ≤ \le ≤ 自己权值 ≤ \le ≤ 右儿子权值。如果要插入节点值为 v v v,只需与根节点的 k e y key key 对比,如果 v ≤ k e y r t v\le key_{rt} v≤keyrt,就去与根节点的左子树对比;如果 v > k e y r t v> key_{rt} v>keyrt,就去与根节点的右儿子对比。这样一直对比,直到对比到了一个空节点,插上去即可。
但是这样就有个问题:这棵树如果退化成一条链(或类似情况),查找一个值或插入一个节点可能就要 Θ ( n ) \Theta(n) Θ(n)。为此,各个聪明的科学家开始想维护二叉查找树平衡的方法,于是就有了伸展树、红黑树、替罪羊树等平衡树。
平衡树上旋 \color{black}\texttt{平衡树上旋} 平衡树上旋
平衡树的经典操作是上旋,分为左旋和右旋。
左旋:设 f f f 节点的右子树为 x x x,把 x x x 左旋即是 x x x 放到 f f f 的位置,然后让 f f f 当 x x x 的左子树,再让 x x x 的左子树当 f f f 的右子树。
右旋:设 f f f 节点的左子树为 x x x,把 x x x 右旋即是 x x x 放到 f f f 的位置,然后让 f f f 当 x x x 的右子树,再让 x x x 的右子树当 f f f 的左子树。图如下:
可见左旋和右旋是互逆操作。旋转操作看似微小,但很多平衡树的实现都是依靠这个操作的,比如本文要讲的 Splaytree \texttt{Splaytree} Splaytree。
Splaytree \color{black}\texttt{Splaytree} Splaytree
Splay \color{black}\texttt{Splay} Splay
Splaytree \texttt{Splaytree} Splaytree 的主要的操作就是 Splay \texttt{Splay} Splay, Splay(x,y) \texttt{Splay(x,y)} Splay(x,y) 表示把 x x x 旋成 y y y 的子节点。在 Splaytree \texttt{Splaytree} Splaytree 中,一般 y = 0 y=0 y=0,即把 x x x 转成 r o o t root root。
Splay \texttt{Splay} Splay 的方法就是不停上旋然后检测,时间复杂度也是 Θ ( log n ) \Theta(\log n) Θ(logn)。每次查询、操作以后都需要把访问的节点 Splay \texttt{Splay} Splay 为根节点,这样就能确保树的大致平衡。最终 Splaytree \texttt{Splaytree} Splaytree 的均摊时间复杂度也就能是 Θ ( log n ) \Theta(\log n) Θ(logn) 的。
然后 Splaytree \texttt{Splaytree} Splaytree 别的内容就都很简单了。
例题 \color{black}\texttt{例题} 例题
普通平衡树 \color{black}\texttt{普通平衡树} 普通平衡树
- 插入