【算法导论】笔记-第十一章 二叉搜索树

第11章 二叉搜索树

11.1 什么是二叉搜索树

  • 二叉搜索树是以一颗二叉树来组织的

  • 设x是二叉搜索树中的一个结点。如果y是x左子树中的一个结点,那么 y . k e y < = x . k e y y.key<=x.key y.key<=x.key。如果y是x左子树中的一个结点,那么 y . k e y > = x . k e y y.key>=x.key y.key>=x.key

  • 中序遍历:输出的子树根的关键字在其左右子树的关键字之间

  • 先序遍历:根的关键字在其左右子树的关键字之前

  • 后序遍历:根的关键字在其左右子树的关键字之后

  • 三种遍历方式子数都是向左再右,不同在于根的位置

  • 中序遍历输出一颗二叉搜索树T中的所有元素

    • 伪代码:INORDER-TREE-WALK(x)

      if x != NIL
          INORDER-TREE-WALK(x.left)
          print x.key
          INORDER-TREE-WALK(x.right)
      
    • 遍历一棵有n个结点的二叉搜索树需要耗费 θ ( n ) \theta(n) θ(n)时间。

11.2 查询二叉搜索树

  • 查找:

    • 伪代码:

      • TREE-SEARCH(x, k)

        if x == NIL or k == x.key
            return x
        if k < x.key
            return TREE-SEARCH(x.left, k)
        else return TREE-SEARCH(x.right, k)
        
      • ITEATIVE-TREE-SEARCH(x, k)

        while x != NIL and k != x.key
            if k<x.key
                x = x.left
            else x = x.right
        return x
        
    • python代码:

      def tree_search(self, root, val):
          if root == None:
              return False
          if root.val == val:
              return True
          elif val < root.val:
              return self.tree_search(root.left, val)
          elif val > root.val:
              return self.tree_search(root.right, val)
      
  • 最大关键字元素和最小关键字元素

    • 思路:如果y是x左子树中的一个结点,那么 y . k e y < = x . k e y y.key<=x.key y.key<=x.key。如果y是x左子树中的一个结点,那么 y . k e y > = x . k e y y.key>=x.key y.key>=x.key

    • 伪代码:

      • TREE-MINIMUM(x)

        while x.left != NIL
            x = x.left
        return x
        
      • TREE-MAXIMUM(x)

        while x.left != NIL
            x = x.right
        return x
        
    • python代码:

      def tree_minimum(self, root):
          if root.left:
              return self.tree_minimum(root.left)
          else:
              return root
      
      def tree_maximum(self, root):
          if root.right:
              return self.tree_maximum(root.right)
          else:
              return root
      
  • 后继和前驱:

    • 给定一棵二叉搜索树中的一个结点,有时需要按中序遍历的次序查找它的后继。如果所有的关键字互不相同,则一个结点x的后继是大于x.key的最小关键字的结点。一棵二叉搜索树的结构允许我们通过没有任何关键字的比较来确定一个结点的后继。

    • 伪代码:TREE-SUCCESSOR(x)

      if x,right != NIL
          return TREE-MINIMUM(x, right)
      y = x.p
      while y != NIL and x == y.right
          x = y
          y = y.p
      return y
      

11.3 插入与删除

  • 插入:

    • 思路:从根开始,x指针记录了一条向下的简单路径,并查找要替换的输入项z的NIL。在找到合适的位置后,我们更新z的父结点以及z的父结点的孩子结点信息从而完成INSERT过程。

    • 伪代码:TREE-INSERT(T, z)

      y = NIL
      x = T.root
      while x != NIL
          y = x
          if z.key < x.key
              x = x.left
          else x = x.right
      z.p = y
      if y == NIL
          T.root = z
      elseif z.key < y.key
          y.left = z
      else y.right = z
      
    • python代码:

      class tree:
      	'''二叉搜索树节点的定义'''
      	def __init__(self, val):
      		self.val = val
      		self.left = None
      		self.right = None
              
      def tree_insert(self, root, val):
          if root == None:
              root = tree(val)
          elif val < root.val:
              root.left = self.tree_insert(root.left, val)
          elif val > root.val:
              root.right = self.tree_insert(root.right, val)
          return root
      
  • 删除:

    • 三种基本情况:

      • 如果z没有孩子结点,那么只是简单地将它删除,并修改它的父结点,用null作为孩子来替换z。
      • 如果z只有一个孩子结点,那么将这个孩子提升到树中z的位置上,并修改它的父结点,用z的孩子来替换z。
      • 如果z有两个孩子结点,那么找z的后继(一定在z的右子树中)y,并让y占据树中 z的位置。z的原来右子树部分成为y的新的右子树,z的原来左子树部分成为y的新的左子树。
    • 子过程TRANSPLANT:为了完成二叉搜索树中结点的DELETE过程,我们需要定义一个子过程TRANSPLANT,它是用另一棵子树来替换一棵子树并成为其双亲的孩子结点。

      • 伪代码:TRANSPLANT(T, u, v)

        if u.p == NIL
            T.root = v
        elseif u == u.p.left
            u.p.left = v
        else u.p.right = v
        if v != NIL
            v.p = u.p
        
    • TREE-DELETE(T, z)

      if z.left == NIL
          TRANSPLANT(T, z, z.right)
      elseif z.right == NIL
          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)
          y.left = z.left
          y.left.p = y
      
    • python代码:

      def tree_delete(self, root, val):
          '''删除二叉搜索树中值为val的点'''
          if root == None:
              return 
          if val < root.val:
              root.left = self.tree_delete(root.left, val)
          elif val > root.val:
              root.right = self.tree_delete(root.right, val)
          # 当val == root.val时,分为三种情况:只有左子树或者只有右子树、有左右子树、即无左子树又无右子树
          else:
              if root.left and root.right:
                  # 既有左子树又有右子树,则需找到右子树中最小值节点
                  temp = self.tree_minimum(root.right)
                  root.val = temp.val
                  # 再把右子树中最小值节点删除
                  root.right = self.tree_delete(root.right, temp.val)
              elif root.right == None and root.left == None:
                  # 左右子树都为空
                  root = None
              elif root.right == None:
                  # 只有左子树
                  root = root.left
              elif root.left == None:
                  # 只有右子树
                  root = root.right
          return root
      
    • 运行时间:在一棵高度为h的二叉搜索树中,DELETE和DELETE过程的运行时间为 O ( h ) O(h) O(h)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

From Star.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值