为了叙述方便,在不引起歧义的情况下,本文把节点关键字的值简称为节点或节点的值。
概念
显然,二叉搜索树(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 node
if 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.right
else:
node = node.left
return node
。
- 如果
最大元和最小元
只要BST非空,那么它总存在最大元和最小元:
- 从根节点
root
出发,沿着左子树一直前进到最后一个非空节点,该节点就是最小元 - 同理,从根节点
root
出发,沿着右子树一直前进到最后一个非空节点,该节点就是最大元BST_MIN(root):
while root.left != null:
root = root.left
return root
BST_MAX(root):
while root.right != null:
root = root.right
return 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.parent
while p_node != null and node == p_node.left:
node = p_node
p_node = node.parent
return p_node
节点
node
的后继就是前驱的对称:BST_SUCCESSOR(node):
if node.right != null:
return BST_MIN(node.right)
p_node = node.parent
while p_node != null and node == p_node.right:
node = p_node
p_node = node.parent
return p_node
时间复杂度:
。
即使存在相同节点的值,我们可以定义前驱和后继为BST_PREDECESSOR(node)
和BST_SUCCESSOR(node)
的值。插入和删除
插入
插入很简单,首先按
BST_SEARCH
的方法找到待插入的节点位置,在判断该节点是其父节点的左子节点还是右子节点。 ``` BST_INSERT(root, x): temp_node = root while root != null:temp_node = root
if root.val < x.val:
root = root.right
else:
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
```
时间复杂度: