博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法导论读书笔记-第十二章-二分检索树
阅读量:6852 次
发布时间:2019-06-26

本文共 3354 字,大约阅读时间需要 11 分钟。

算法导论第12章 二叉搜索树

12.1 什么是二叉搜索树

二叉搜索树以二叉树的结构组织, 每个结点包含key, 卫星数据, left(指向左孩子), right(指向右孩子), p(指向双亲). 二叉搜索树满足以下性质: 对于每个结点\(x\) , 其左子树上的结点不大于\(x\) , 右子树上的结点不小于\(x\) .

中序遍历二叉搜索树, 可以按序输出树中所有关键字.

# 调用下面的过程inorder_tree_walk(T.root)可以按序输出二叉搜索树T中所有元素inorder_tree_walk(x):  if x is not None:    inorder_tree_walk(x.left)    print x.key    inorder_tree_walk(x.right)

定理12.1 : 如果\(x\) 是一棵有n个结点子树的根, 那么调用 inorder_tree_walk(x) 需要\(\Theta(n)\) 时间.

12.2 查询二叉搜索树

# 调用下面的过程recurrsive_tree_search(x,k), 其中x为根结点, k为关键字.# 如果关键字为k的结点存在, 返回一个指向关键字为k的结点的引用; 否则返回Nonerecurrsive_tree_search(x,k):  if (x is None) or (k == x.key):    return x  if k < x.key:    return tree_search(x.left)  else:    return tree_search(x.right)
# 调用下面的过程iterative_tree_search(x,k), 其中x为根结点, k为关键字.# 如果关键字为k的结点存在, 返回一个指向关键字为k的结点的引用; 否则返回Noneiterative_tree_search(x,k):  while (x is not None) and (k != x.key):    if k < x.key:      x = x.left    else:      x = x.right  return x

MAXIMUM & MINIMUM

# x为根结点# 返回最小结点tree_minimum(x):  while x.left is not None:    x = x.left    return x
# x为根结点# 返回最大结点tree_maximum(x):  while x.right is not None:    x = x.right    return x

以上过程在一棵高度为h的树上均能在O(h)时间内执行完.

SUCCESSOR & PREDECESSOR

# x是根结点# 若x的后继存在, 返回其后继结点# 若x是最大关键字, 返回Nonetree_successor(x):  # 若x的右子树非空, 则x的后继为右子树中的最小结点  if x.right is not None:     return tree_minimum(x.right)  # 若x的右子树为空, 则x是某棵树T的最大结点(最右下角)  # 找到满足x是其最右下角的最大的子树T, 则x的结点为T.p.  # 具体做法是一直往父结点找, 一直找到一个有左子树的根结点T.  y = x.p  while (y is not None) and (x == y.right):    x = y    y = y.p  return y
# x是根结点# 若x的前驱存在, 返回其前驱结点# 若x是最小关键字, 返回Nonetree_predecessor(x):  # 若x的左子树非空, 则x的前驱为左子树中的最大结点  if x.left is not None:     return tree_maximum(x.left)  # 若x的左子树为空, 则x是某棵树T的最小结点(最左下角)  # 找到满足x是其最左下角的最大的子树T, 则x的结点为T.p.  # 具体做法是一直往父结点找, 一直找到一个有右子树的根结点T.  y = x.p  while (y is not None) and (x == y.left):    x = y    y = y.p  return y

定理12.2 : 在一棵高度为h的二叉搜索树上, 动态集合上的操作SEARCH, MINIMUM, MAXIMUM, SUCCESSOR, PREDECESSOR可以在O(h)时间内完成.

12.3 插入和删除

INSERT

# T是一棵二叉搜索树(根结点)# z是一个新结点, 其中z.key=v, z.left=None, z.right=Nonetree_insert(T, z):  # y用来找z的父节点  y = None  # x用来遍历  x = T.root  # 确定父节点  while x is not None:    y = x    if z.key < x.key:      x = x.left    else:      x = x.right  # 插入  z.p = y  if y is None:    T.root = z  else if z.key < y.key:    y.left = z  else:    y.right = z

DELETE

从一棵二叉搜索树T中删除一个结点z分为三种基本情况:

  • 若z没有孩子结点, 简单删除并修改其父结点.
  • 若z只有一个孩子结点, 用这个孩子代替z的位置.
  • 若z有两个孩子, 找z的后继(或前驱)y, 并让y代替z的位置.

实际算法中可以这样实现:

  • 若z没有左孩子, 则用右孩子代替z的位置. (包括了没有右孩子的情况).
  • 若z有左孩子:
    • 若z没有右孩子, 则用左孩子代替z的位置.
    • 若z有右孩子, 找出z的后继y:
      • 若y是z的右孩子, 用y替换z的位置.
      • 若y不是z的右孩子, 先用y的右孩子替换y, 再用y替换z.
# 用一棵以v为根结点的子树替换一棵以u为根结点的子树# u的双亲变成v的双亲, v成为u的双亲的相应孩子# 注: v可以看作是一棵新的树, 可以不是原树T的子树transplant(T, u, v):  # u是T的根  if u.p is None:    T.root = v  # u是父结点的左孩子  else if u == u.p.left:    u.p.left = v  # u是父结点的右孩子  else:    u.p.right = v  if v is not None:    v.p = u.p
# 从二叉搜索树T中删除结点z# 流程见上面实际算法的实现tree_delete(T, z):  if z.left is None:    transplant(T, z, z.right)  else if z.right is None:    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

定理12.3 : 在一棵高度为h的二叉搜索树上, 实现动态集合操作INSERT和DELETE的运行时间均为O(h).

12.4 随机构建二叉搜索树

随机构建二叉搜索树: 按随机次序插入这些关键字到一棵初始的空树中而生成的树.

定理12.4 : 一棵有n个不同关键字的随机构建二叉搜索树的期望高度为O(lgn).

转载于:https://www.cnblogs.com/ayistar/p/7838962.html

你可能感兴趣的文章
LeetCode算法题-Implement Queue Using Stacks(Java实现)
查看>>
spring 事务
查看>>
[转自知乎] 如何成为一个优秀的程序员,而不是一个优秀的码农?
查看>>
java abstract class和interface有什么区别
查看>>
虚拟机桥接模式不能上网
查看>>
lodash.js 学习记录
查看>>
1.4 Genymotion模拟器安装
查看>>
简说设计模式——外观模式
查看>>
简说设计模式——模板方法模式
查看>>
php 图片写字
查看>>
linux之权限
查看>>
Deep Learning(深度学习)学习笔记整理系列之(三)
查看>>
网页布局之Div vs Table (2)
查看>>
可变参数列表
查看>>
BouncyCastle.Crypto的RSA算法调用源码
查看>>
vs2017 + Python3.6 +Django1.11 连接mysql数据库
查看>>
一张思维导图带你梳理HashMap相关知识
查看>>
MVC 从Excel导入到DataTable
查看>>
Symbol
查看>>
Selenium WebDriver + IE11 问题汇总
查看>>