1、什么是二叉搜索树(BST)
一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
2、 判断 BST 的合法性
递归实现思路:
主函数isValidBST传入两个参数null,表示刚开始的左右边界是inf(无穷)
helper设计理念是二叉树中,子树中的所有节点值都在(lower,upper)之间
(也可以使用中序遍历——递增进行设计!)
class Solution {
public boolean isValidBST(TreeNode root) {
return helper(root, null, null);
}
public boolean helper(TreeNode node, Integer lower, Integer upper) {
if (node == null) return true;
int val = node.val;
// 若 val 不符合 lower 和 upper 的限制,说明不是合法 BST
if (lower != null && val <= lower) return false;
if (upper != null && val >= upper) return false;
// 限定左子树的最大值是 root.val,右子树的最小值是 root.val
return helper(node.left, lower, val) && helper(node.right, val, upper);
}
}
3、在 BST 中搜索一个数
利用了二叉搜索树的基本性质进行设计
boolean isInBST(TreeNode root, int target) {
if (root == null) return false;
if (root.val == target)
return true;
if (root.val < target)
return isInBST(root.right, target);
if (root.val > target)
return isInBST(root.left, target);
// root 该做的事做完了,顺带把框架也完成了,妙
}
4、 在 BST 中插入一个数
注意:
一旦涉及「改」,函数就要返回TreeNode类型,并且对递归调用的返回值进行接收。
TreeNode insertIntoBST(TreeNode root, int val) {
// 找到空位置插入新节点
if (root == null) return new TreeNode(val);
// if (root.val == val)
// BST 中一般不会插入已存在元素
if (root.val < val)
root.right = insertIntoBST(root.right, val);
if (root.val > val)
root.left = insertIntoBST(root.left, val);
return root;
}
5、在 BST 中删除一个数
主要分为3种情况
1)删除的节点下没有子树
2)删除的节点下有一棵子树
3)删除的节点下有二棵子树
如果是第一种情况就直接删去就好
如果是第二种情况就直接子树上移
如果是第三种情况就将该节点的左子树中的最大值,替换该节点后进行删除
或者该节点的右子树中的最小值,替换该节点后进行删除
对于3种情况如下图所示
对于第一种情况来说:我们要删除节点5(root),直接 return root.right 即可。
对于第二种情况来说:我们要删除节点5(root),直接 return root.left 即可。
对于第三种情况来说:我们要删除节点5(root),只需将root的左子树放到root的右子树的最下面的左叶子节点的左子树上即可。如图所示:
最后,我们将整个流程串起来,即为总体的逻辑流程。
class Solution {
TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null;
if (root.val == key) {
// 这两个 if 把情况 1 和 2 都正确处理了
if (root.left == null) return root.right;
if (root.right == null) return root.left;
// 处理情况 3
TreeNode minNode = root.right;
while (minNode.left != null) {
minNode = minNode.left;
}
minNode.left = root.left;
return root.right;
} else if (root.val > key) {
//递归时子树的连接
root.left = deleteNode(root.left, key);
} else if (root.val < key) {
//递归时子树的连接
root.right = deleteNode(root.right, key);
}
return root;
}
}