数据结构之二叉搜索树

纸上得来终觉浅,绝知此事要躬行

性质

对于节点x

  • 如果y是x的左孩子,则 x.key>=y.key
  • 如果y是x的右孩子,则 x.key<=y.key
    如图1:
    这里写图片描述

查询操作

  • 遍历操作:inorder-tree-walk(x)——中序, preorder-tree-walk(x)——先序,postorder-tree-walk(x)——后续
inorder-tree-walk(x) {
  if(x != null) {
    inorder-tree-walk(x.left)
    print(x.key)
    inorder-tree-walk(x.right)
  }
}
  • 查询操作:tree-search(x,k) :给定值k,返回值等于k的节点
tree-search(x,k){
  if(x ==null || x.key == k) return x
  else if(k > x.key) return tree-search(x.right,k)
  else return tree-search(x.left,k)
}
  • 查询操作:
    • 1、tree-minimum(x),tree-maximum(x)————给定节点,返回相应节点
    • 2、tree-successor(x),tree-predecessor(x)————给定节点,返回排序后的相应后一个或前一个值的节点

如图2: 6的后继是7;13的后继是15。
这里写图片描述

tree-successor(x) {
  if(x.right != null) return tree-minimum(x.right)

  y = x.parent
  while(y.right == x && y != null) {
    x = y
    y = y.parent
  }

  return y
}

修改操作

  • 修改操作:tree-insert(T,x)————输入树T,和节点x
//初始调用树节点为  T.root
tree-insert(T,x) {
  if(T == null) T = x

  else if(x > T.key) {
    if(T.right != null) tree-insert(T.right,x)
    else T.right = x
  }

  else {
    if(T.left != null) tree-insert(T.left,x)
    else T.left = x
  }
}
  • 修改操作:tree-delete(T,z)————输入树T,和节点z

分析:删除操作可分为3种情况

  • 1、如果z没有孩子节点,直接删除z节点
  • 2、如果z只有一个节点,只需要把z.parent指向z.left或者z.right
  • 3、如果z有两个节点,我们先找到z节点的后继节点y(一定在z的右子树上,根据二叉排序树的性质),之后用y代替z节点。z的左子树做为y的左子树,z的右子树做为y的右子树。这里需要考虑两种情况:y == z.right ; y != z.right。

量化各种情况:

  • 1、if z.left == null,没有左节点(图3.(a)) : 我们用z.right代替x节点。如果z.right != null,为一个右节点的情况;如果z.right == null,为没有节点的情况。
  • 2、if z.left != null,只有一个左节点(图3.(b)) :我们用z.left节点代替z节点。
  • 3、否则,z左右孩子都有。我们先找出z的后继y,一定是z的右子树上的节点,且此节点没有左孩子。这时候需要分两种情况:
    • (1)、z.right == y (图3.(c)),只需要用y节点代替x节点。(外加变动左孩子的操作)
    • (2)、z.right != y (图3.(d)),先用y.right节点代替y节点;再用y节点代替z节点。(外加变动左孩子的操作)

图3:

这里写图片描述
代码实现

定义一个用v节点替换u节点的操作:只修改了父节点指向,具体左右孩子的变动由调用者决定。

transplant(T, u, v) {
      //u的父节点指向v
  if u.p == null        // 替换根节点的情况
      T.root = v
  else if u == u.p.left // 替换的节点是父节点的左孩子
      u.p.left = v
  esle if u.p.right = v

    //v的父节点指向u父节点
  if v != null          // 节点v不为空节点
      v.p = u.p
}
tree-delete(T,z) {
  if z.left == null
      transplant(T, z, z.right)
  else if z.right == null
      transplant(T, z, z.left)
  else {
    y = tree-minimum(z.right)
    if(y.p != z) {
         transplant(T, y, y.right)
         y.right = z.right // 变动右孩子的操作
         y.right.p = y
    }  
    transplant(T, z, y)
    z.left = y.left        // 变动左孩子的操作
    z.left.p = y
  }
}

完全理解此代码是建立在自行构造数据跑一跑删除节点的代码的基础上的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值