为了叙述方便,在不引起歧义的情况下,本文把节点关键字的值简称为节点或节点的值。
概念
显然,二叉搜索树(Binary Search Tree)是一颗二叉树。但与普通的二叉树不同的是,对于BST的每个节点,它的左子树中的所有节点(如果有的话)的值都不大于该节点的值;它的右子树中的所有节点(如果有的话)的值都不小于该节点的值。
TREENODE:parent,left,right,val
查询二叉搜索树
查找
由于BST的特殊结构,查找操作是非常简单的:
- 判断当前节点
node是否为空节点;若是,则返回null(表示没找到target),否则进行第二步。 - 比较
node的值val与目标值target的大小- 如果
val < target:那么在node右子树node.right中查找,返回第一步 - 如果
val > target:那么在node左子树node.left中查找,返回第一步 - 如果
val == target:返回node(表示存在)BST_SEARCH(node, target):if node == null or node.val == target:return nodeif node.val < target:return BST_SEARCH(node.right, target)else:return BST_SEARCH(node.left, target)
时间复杂度:BST_SEARCH(node, target):while node != null and node.val != target:if node.val < target:node = node.rightelse:node = node.leftreturn node
。
- 如果
最大元和最小元
只要BST非空,那么它总存在最大元和最小元:
- 从根节点
root出发,沿着左子树一直前进到最后一个非空节点,该节点就是最小元 - 同理,从根节点
root出发,沿着右子树一直前进到最后一个非空节点,该节点就是最大元BST_MIN(root):while root.left != null:root = root.leftreturn root
BST_MAX(root):while root.right != null:root = root.rightreturn root
后继和前驱
如果所有节点互不相同,一个节点的后继是大于该节点的最小节点,前驱是小于该节点的最大节点。把BST看成一个升序数组(事实上,就是中序遍历BST生成的数组),那么一个节点的前驱就是前一个节点,后继就是后一个节点。显然,最小的节点没有前驱,最大的节点没有后继。
回到BST中,一个节点node的前驱:
- 如果
node存在左子树,那么node的前驱就是node.left中最大元素 - 如果
node不存在左子树,且node的父节点node.parent存在:- 若
node是node.parent的左子树,令node = node.parent,重复此行为 - 若
node是node.parent的右子树,返回其父节点node.parent
- 若
如果
node不存在左子树,且node的父节点不存在,那么node没有后继BST_PREDECESSOR(node):if node.left != null:return BST_MAX(node.left)p_node = node.parentwhile p_node != null and node == p_node.left:node = p_nodep_node = node.parentreturn p_node
节点
node的后继就是前驱的对称:BST_SUCCESSOR(node):if node.right != null:return BST_MIN(node.right)p_node = node.parentwhile p_node != null and node == p_node.right:node = p_nodep_node = node.parentreturn p_node
时间复杂度:
。
即使存在相同节点的值,我们可以定义前驱和后继为BST_PREDECESSOR(node)和BST_SUCCESSOR(node)的值。插入和删除
插入
插入很简单,首先按
BST_SEARCH的方法找到待插入的节点位置,在判断该节点是其父节点的左子节点还是右子节点。 ``` BST_INSERT(root, x): temp_node = root while root != null:temp_node = rootif root.val < x.val:root = root.rightelse:root = root.left
x.parent = temp_node if temp_node == null:
return x # 空树返回x
else if temp_node.val < x.val:
temp_node.right = x
else:
temp_node.left = x
return null # 表示不是空树
<a name="u574z"></a>### 删除删除节点`x`时,可以分三种情况讨论:- `x`没有子节点:直接删除`x`即可- `x`只有一个子节点:直接将子节点放到`x`的位置上即可- `x`有两个子节点:那么`x`的后继必然在右子树中,命名为`y`。`y`的左子节点必然是空的,将`y`与`x`的位置交换,将`y.right`放到原来`y`的位置上
BST_DELETE(root, x):
if x.left == null and x.right == null:
if x == x.parent.left:
x.parent.left = null
else:
x.parent.right = null
else if x.left == null:
if x == x.parent.left:
x.parent.left = x.right
x.right.parent = x.parent
else:
x.parent.right = x.right
x.right.parent = x.parent
else if x.right == null:
if x == x.parent.left:
x.parent.left = x.left
x.left.parent = x.parent
else:
x.parent.right = x.left
x.left.parent = x.parent
else:
y = BST_SUCCESSOR(x)
if y == x.right:
x.parent.left = y
y.parent = x.parent
y.left = x.left
else:
y.parent.left = y.right
y.right.parent = y.parent
y.left = x.left
y.right = x.right
y.left.parent = y
y.right.parent = y
y.parent = x.parent
if x == x.parent.left:
y.parent.left = y
else:
y.parent.right = y
```
时间复杂度:
