二分搜索树
二分搜索树势一颗典型的二叉树,二分搜索树根节点的值大于左孩子节点的值,小于右孩子节点的值,插入/删除/查找的时间复杂度都是log(n)
二叉搜索树的创建,插入,删除
创建,插入
/**
* 思路:
* 首先初始化第一个节点,然后第二个节点要插入树中需要找到要插入位置的根节点,
* 有一个查找的过程,然后根据值的大小分别放在左右子树
* @param a
* @param n
* @return
*/
public static BST create(int [] a,int n) {
BST root = new BST(a[0]);
for (int i = 1; i < n; i++) {
BST searchNode = search(root,a[i]);
if (searchNode.val > a[i]) {
searchNode.left = new BST(a[i]);
}else if (searchNode.val < a[i]) {
searchNode.right = new BST(a[i]);
}
}
return root;
}
public static BST search(BST root,int val) {
if (root == null) {
return null;
}
if (val > root.val && root.right != null) {
return search(root.right,val);
}
if (val < root.val && root.left != null){
return search(root.left,val);
}
return root;
}
删除
/**
*思路:
*1.如果要删除的节点是叶节点,找到要删除节点的父亲节点,直接删除
*2.如果要删除的节点只有左子树,或者右子树,父亲节点指向孩子的左节点或者右节点
*3.如果要删除的节点有左右子树,找到删除的节点的右子树的最左节点,替换到该节点
*/
public static BST searchParent(BST root,int val) {
if (root == null) {
return null;
}
if (root.left != null && root.val > val){
if (root.left.val == val ) {
return root;
}
return searchParent(root.left,val);
}
if (root.right != null && root.val < val){
if (root.right.val == val ) {
return root;
}
return searchParent(root.right,val);
}
return null;
}
public static boolean deleteNode(BST root,int val) {
//找到父亲节点
BST searchNode = searchParent(root,val);
if (searchNode == null) {
return false;
}
//找到要删除的节点
BST deleteNode = null;
boolean isLeftCHilde = false;
if (searchNode.left != null && searchNode.left.val == val) {
deleteNode = searchNode.left;
isLeftCHilde = true;
}
if (searchNode.right != null && searchNode.right.val == val) {
deleteNode = searchNode.right;
}
if (deleteNode.left == null && deleteNode.right == null) {
//要删除的节点无孩子节点
if (isLeftCHilde) {
searchNode.left = null;
}else {
searchNode.right = null;
}
}else if (deleteNode.left != null && deleteNode.right == null) {
//要删除的节点只有左孩子节点
if (isLeftCHilde) {
searchNode.left = deleteNode.left;
}else {
searchNode.right = deleteNode.left;
}
}else if (deleteNode.left == null && deleteNode.right != null) {
//要删除的节点只有右孩子节点
if (isLeftCHilde) {
searchNode.left = deleteNode.right;
}else {
searchNode.right = deleteNode.right;
}
}else {
//要删除的节点有左,右孩子节点
BST mLeftNode = searchML(deleteNode.right);
deleteNode.val = mLeftNode.val;
return deleteNode(deleteNode.right,mLeftNode.val);
}
return true;
}
判定一棵树是否是二分搜索树
/**
* 98. Validate Binary Search Tree
* 判定一棵树是否是二分搜索树
* 思路:
* 二分搜索树的判定原则:
* 根节点>左子树
* 根节点 <右子树
*
* 注意:递归的时候,有个隐含条件:
* 左子树的右孩子节点是要小于根节点的
* 右子树的左孩子节点是要大于根节点的
* @param root
* @return
public boolean isValidBST(TreeNode root) {
return isValidBST(root,null,null);
}
public boolean isValidBST(TreeNode root,Integer max,Integer min) {
if (root == null) {
return true;
}
if (max != null && root.val > max) {
return false;
}
if (min != null && root.val < min) {
return false;
}
return isValidBST(root.left,root.val,min) && isValidBST(root.right,max,root.val);
}
求二分搜索树最小公共祖先
/**
* 求最小公共祖先
* 根据二分搜索树的特点:
* 根节点的值大于>左子树的值
* 根节点的值大于<右子树的值
* 如果:
* 两个节点的值在根节点的两边,或者其中一个等于根节点,等于那么最小公共祖先就是根节点
* 如果在一边,则去子树中继续寻找
*
* @param root
* @param p
* @param q
* @return
*/
public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p == null || q == null) {
return null;
}
//左子树寻找
if (root.val > p.val && root.val >q.val) {
return lowestCommonAncestor1(root.left,p,q);
}
if (root.val < p.val && root.val <q.val) {
return lowestCommonAncestor1(root.right,p,q);
}
return root;
}