第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)
-