一、二叉搜索树的定义与基本操作:
什么是二叉搜索树?
二叉搜索树又叫二叉排序树和二叉查找树,对于二叉树中的结点的属性值是按照一定规律排列的
二叉搜索树的查找操作:
二叉搜索树的插入操作:
二叉搜索树的删除操作:
对于删除操作比较复杂,我们可以分为以下三种情况进行讨论
-
待删除的结点为叶子结点
找到要删除的结点,直接删除即可
-
待删除的结点只有左子树或右子树
将该结点的父节点指向该节点的子树即可
-
待删除的结点既有左子树又有右子树
将要删除节点 node 位置上替换成左子树最右边的节点或者右子树最左边的节点【左子树的最大值或右子树的最小值】
通过几道算法题来巩固对二叉搜索树的理解:
二、二叉搜索树相关算法题
1.LeetCode 700:二叉搜索树中的搜索
📝 解题思路:
对于搜索二叉树的查找练习
📖 Java版本:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
//当前结点为空
if(root == null){
return null;
}
if(root.val == val){
return root;
}else if(root.val > val){
return searchBST(root.left, val);
}else{
return searchBST(root.right, val);
}
}
}
2.LeetCode 235: 二叉搜索树的最近公共祖先
📝 解题思路:
(1)利用二叉搜索树的性质,我们可以很快的找到两个目标结点
(2)对于这两个结点的位置可能有三种情况:
(1)都在左子树上
(2)都在右子树上
(3)一个在左子树上一个在右子树上
📖 Java版本:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
/**
对于两个目标结点的位置,可能有三种情况:
(1)都在左子树上
(2)都在右子树上
(3)一个在左子树上一个在右子树上
*/
if(p.val > root.val && q.val > root.val){
return lowestCommonAncestor(root.right, p, q);
}else if(p.val < root.val && q.val < root.val){
return lowestCommonAncestor(root.left, p, q);
}
return root;
}
}
3.LeetCode 98:验证二叉搜索树
📝 解题思路:
- 方案一:利用二叉搜索树中序遍历的有序性
(1)中序遍历二叉搜索树
(2)创建一个集合保存结点的值
(3)最后遍历集合验证序列是否满足从小到大的排序
Java版本:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
private List<Integer> res = new ArrayList<Integer>();
public void inOrder(TreeNode root){
if(root == null){
return;
}
inOrder(root.left);
res.add(root.val);
inOrder(root.right);
}
public boolean isValidBST(TreeNode root) {
/**
利用搜索二叉树中序遍历的结果是一个有序的序列来验证是否为搜索二叉树
利用一个集合来维护搜索二叉树的结点值,最后遍历这个集合检验其有序性
*/
//中序遍历二叉树
inOrder(root);
//遍历集合
for(int i = 1; i < res.size(); i++){
if(res.get(i) <= res.get(i - 1)){
return false;
}
}
return true;
}
}
- 方案二:根据二叉树左子树的结点值都小于根结点的值,右子树的值都大于根结点的值
(1)如果根结点的值比最大长整型的值大或比最小长整型的值小都说明不满足搜索二叉树的性质
(2)左孩子的值不小于根结点的值或右孩子不大于根结点的值,也都说明不满足搜索二叉树的性质
Java版本:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root, long num1, long num2){
if(root == null){
return true;
}
if(root.val <= num1 || root.val >= num2){
return false;
}
return isValidBST(root.left, num1, root.val) && isValidBST(root.right, root.val, num2);
}
public boolean isValidBST(TreeNode root){
return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
}
因为第一个版本要维护一个集合,而且需要遍历集合所以两个算法后者更优