真正的操作,其实大可不必按照理解的思路进行旋转
可以类比一个魔方,如果是组装工人,不需要根据规则旋转,而是直接组装。
将需要旋转的祖孙三代,g p v 按照中序遍历重新命名 a < b < c 然后对于g p v 的孩子们(不超过四个) 按照中序遍历次序,从新命名 T0 < T1 < T2 < T3 于是可以重新组装
3+4重构。
对于重命名的规则,可以分四种情况分别列举。
至此,删除与插入操作(包括子操作旋转操作)迎刃而解。
AVL树有什么缺点呢?
需要单独记录平衡因子,需要改造元素结构并且额外封装。 单次动态调整之后,全书的拓扑结构变化量可高达Ω(logn)
数据结构(下) 第八章 高级搜索树 一 伸展树
对于一些元素,很可能要经常对其进行访问,或者对与其相邻的一些元素经常访问,因此可以进行优化。
(与链表进行比较: 某些链表的元素会被集中访问,因此每次访问一个元素可以将之移动到最前端,可以提高访问效率。)
回到BST,可以将某一段时间内经常访问的元素移动到树根的位置。(利用zig 与 zag 旋转)
但这样会遇到只有一个狭长分支的最坏情况。
怎么优化呢?
通过zig zag旋转(AVL树的双旋调整) 通过zig-zag 或者 zag-zag
(相当于不直接旋转所寻找的那个节点在的一级,而是从他的父节点下手旋转)
当需要zigzig或者zagzag(也就是在分支在一侧的情况) 旋转与avl树相同。
代码实现: splay函数:
分情况:1,当前孩子为右孩子还是做孩子
2, 当前孩子的父亲为右孩子还是左孩子 分情况进行zig 、 zag 旋转。
旋转细节:同avl,可以直接进行拆开重接,而非生搬硬套模拟旋转过程
注:还需要考虑没有祖父节点的情况(即只需要直接旋转)
查找函数:查找此节点存在否,若存在,则返回splay后的节点,否则splay与要查找值相似的节点并返回其接口。 插入:
首先调用search(即首先将相似节点splay到了根节点,然后进行插入) 因此可以直接在根节点处进行插入。
删除算法:
依然是调用了search(),所以根节点必为树根
因此直接在树根处进行删除,然后选择左右任意子树中最小的节点作为根节点。
—————————————————————— B树:
每个节点未必只有两个分差 底层节点的深度相同 更宽、更矮。
超级节点的概念:多个关键码位于一个节点。
例如:
为什么如此(这样与上图不是等价吗?)
优点:针对外部查找大大提高了输入输出(I/O)效率
每次访问一个关键码可以读出一组数据,相比于一个节点一个数据,这样的效率提高了很多。
例如有1G的数据,单次查找一个数据,
如果二叉树,则需要log(2,10^9)=30 次,而如果以关键节点有256个关键码的B树,只需要查找log(256,10^9)<4 次。
B树的阶: 阶数=路数
B树的外部节点(也就是叶子节点的下一个节点(空节点))深度相同,且即B树的高度。
B树的命名: