数据结构 C++:树、查找二叉树、平衡树(AVL树)、伸展树(SplayTree)总结

相关术语:

  • root 根
  • edge 边
  • child 子节点
  • parent 父节点
  • leaf 叶节点
  • sibling 兄弟节点
  • path 路径:从节点n1 到 nk的路径定义为:节点n1 n2 n3 … nk 的序列, 使得对于1<=i<k的节点ni是ni+1的父节点。路径的长(length)即为该路径上的边的数量, 即k-1.
  • depth
    深度:从根节点到ni的唯一路径的长。特别的,根的深度为0.
  • internal path length 内部路径长:一棵树的所有节点的深度的和称为内部路径长。
  • height 高度:从ni到一片树叶的最长路径的长。特别的,叶节点的高度都为0.
  • height of tree 树的高度:即根节点的高度
  • depth of tree 树的深度:即树的最深的节点的深度(树的深度=树的高度
  • ancestor 祖先
  • descendant 后裔
  • proper ancestor
  • proper descendant
  • preorder traversal 先序遍历:对节点的处理在对其子节点的处理之前
  • postorder traversal 后序遍历:对节点的处理在对其子节点的处理之后
  • inorder traversal 中序遍历:先处理左节点,再根节点,最后右节点(对于二叉树)
  • level-order traversal 层序遍历:深度为D的节点要比深度为D+1的节点之前处理

相关结论:

  • 高度为H的二叉树,最多有2^(H+1)-1个节点
  • 深度为d的二叉树,最多有2^d个叶节点
    • 具有L个叶节点的二叉树,至少是⌈logL⌉
  • N个节点的二叉树中,存在N+1个空指针代表的N+1个子节点
  • 满节点(full node) 是具有两个儿子的节点。满节点的个数 + 1 = 非空二叉树的叶节点的个数

-------------------->相关实现C++,放在GitHub了<--------------------

二叉查找树

结构性质

对于一个含有元素X的节点,其左节点的元素小于X,其右节点的元素大于X。

基本操作

平均运行时间都是O(logN)

Find

FindMin/FindMax

Insert

重复元素的插入可以通过在节点中附加一个用于指示重复次数的域。

Delete

  1. 对与叶节点,直接删除
  2. 只有一个子节点的节点:将其父节点中指向该节点的指针,指向该节点的子节点,从而绕过该节点。再删除。
  3. 有两个子节点的节点:用右子树的最小元素替代该节点,然后递归地删除那个节点。(右子树中的最小元素不可能有左子节点,所以第二次删除将是容易的).
    (或用左子树中的最大节点代替该节点)

平衡树AVL树

结构性质

AVL树是带有平衡条件的二叉查找树,它保持树的深度是O(logN)
一棵AVL树的每个节点的左子树和右子树的高度最多差1。

基本操作

Insert⭐

插入一个节点可能破坏AVL树的特性。树的特性被破坏后,可以通过旋转(rotation)来进行修正。
导致不平衡的四种情况:

  1. 对a节点的左子节点的左子树进行一次插入
  2. 对a节点的右子节点的右子树进行一次插入
  3. 对a节点的左子节点的右子树进行一次插入
  4. 对a节点的右子节点的左子树进行一次插入
  • 前两中情况是互相对称的,发生在“外侧”,可以用一次 单旋转(single rotation)来完成调整
  • 后两种情况是互相对称的,发生在“内侧”,可以用稍复杂的 双旋转(double rotation)来完成调整
  • 插入后,一次旋转操作总是使整棵树的高度与原来树的高度相同,通向根节点的路径的高度不需要进一步的修正,因而总是只需要一次旋转操作
单旋转:

在这里插入图片描述

双旋转:

在这里插入图片描述

可以将Y当作是一个根k2和两颗子树B,C构成的子树。B或C中有一棵比D深两层(或者B,C,D都为空),即使不知到是那一颗也没关系,这不影响操作。
双旋转可以用两次单旋转来完成:

singleRotation(k1);
singleRotation(k3);

Delete⭐

执行完普通查找二叉树的删除操作后,在根节点到删除节点的路径上,检查需要旋转的子树并对其进行旋转。

伸展树SplayTree

结构性质

  • 基本思想:当一个节点被访问后,要经过一系列AVL旋转树的旋转放到根上。
  • 我们要在访问路径上的每一个节点和他们的父节点实施旋转,这会将被访问节点一直推向根。

基本操作

Find⭐

使用**展开(Splay)**实现将被访问的节点X推向根节点:

  • 对访问路径上的每个点执行操作:
  • 如果X的父节点是根,只接旋转X和根节点
  • 否则说明其有祖父节点:
    • 之字形(zig-zag)情形:X是右子节点,X的父节点是左子节点(以及对称的另一种情况)。执行一次双旋转
      在这里插入图片描述

    • 一字型(zig-zig)情形:X是左子节点,X的父节点也是左子节点(以及对称的另一种情况)。执行一次一字型旋转
      (其实可以执行三次单旋转来完成,分别对singleRotation( P ) singlRotation(G) singleRotation(G)
      一字型(zig-zig)情形

实现原创:

  1. 递归地向下寻找时记录路径
  2. 递归返回时,返回所处理的节点与X节点的路径长
  3. 如果下一层递归返回上来的路径长为1,则说明该层递归所处理的节点与X节点的路径长为2,可以进行旋转操作,然后返回0
  4. 如果没由找到,则返回一个大于等于2的数,使旋转操作无法执行。

FindMin/FindMax

Insert

Delete

  • 将该节点X旋转到根上。
  • 删除该节点则得到左子树TL和右子树TR。
  • 将TL中最大的元素旋转到TL的根上,此时,TL的没有右子节点。
  • 使TR成为TL的根的右子节点,则完成删除。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绫零依

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值