1. 概念
二叉搜索树是特殊的二叉树,也叫二叉排序树,它的特点是:每个结点的左子树上的所有结点的值都小于这个结点的值,右子树上的所有结点的值都大于这个结点的值,另外所有的左子树和右子树也分别为二叉搜索树,如图:
2. 二叉搜索树的操作
2.1 查找
根据二叉搜索树的性质来,很容易可以理解查找的逻辑:从根结点开始,比较结点的值与待查找的值,如果待查找的值比根结点的值小,说明待查找的结点一定在树的左边,如图
当然也有其他情况:根结点为空、该树不存在要查找的这个结点,这个时候直接返回null就可以了
public TreeNode search(int key) {
TreeNode cur = root;
while (cur != null) {
if (cur.val > key) {
cur = cur.left;
} else if (cur.val < key) {
cur = cur.right;
} else {
return cur;
}
}
return null;
}
2.2 插入
插入的前提:插入一定是在叶子结点上插入,因为插入之后也要满足二叉搜索树的性质,插入之前需要查找要插入的位置,而查找的逻辑和刚才的逻辑一样
2.3 删除
删除的情况比较复杂,主要分为以下情况(假设del为要删除的结点,parent为del的父亲结点):
1、cur.left == null
- 1、del 是root
- 2、del 不是root,del是parent.left
- 3、del 不是root,del是parent.right
2、cur.right == null
- 1、del 是root
- 2、del 不是root,del是parent.left
- 3、del 不是root,del是parent.right
3、cur.left != null && cur.right != null
下面我们一个一个分析
情况1:del.left==null
-
情况1.1:del是根结点root,删除逻辑:root =del.right
-
情况1.2 :del不是根结点,del是parent.left删除逻辑:parent.left=del.right
-
情况1.3:del不是根结点,del是parent.right,删除逻辑:parent.right=del.right
情况2:del.right==null -
情况2.1:del是根结点root,删除逻辑root = del.left
-
情况2.2:del不是根结点,del是parent.left,删除逻辑:parent.left = del.left
-
情况2.3:del不是根结点,del是parent.right,删除逻辑:parent.right = del.left
情况3:要删除的结点左右都不为空
如图
两种方法:
1.找到del的左树找值最大的结点,将del结点的值替换成这个值,接着删除这个最大值的结点,如上图的37,删除之后的情况如下
2.找到del的右子树找值最小的结点,将del结点的值替换成这个值,接着删除这个最小值的结点,如上图的45,删除之后的结果如下
3. 全部代码
public class BinarySearchTree {
static class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val) {
this.val = val;
}
}
public TreeNode root;
/**
* 查找
*
* @return
*/
public TreeNode find(int key) {
TreeNode cur = root;
while (cur != null) {
if (cur.val > key) {
cur = cur.left;
} else if (cur.val < key) {
cur = cur.right;
} else {
return cur;
}
}
return null;
}
//插入
public void insert(int key) {
TreeNode cur = root;
TreeNode parent = null;
TreeNode newNode = new TreeNode(key);
if (cur == null) {
root = newNode;
return;
}
while (cur != null) {
if (cur.val > key) {
parent = cur;
cur = cur.left;
} else if (cur.val < key) {
parent = cur;
cur = cur.right;
} else {
return;
}
}
if (parent.val > key) {
parent.left = newNode;
} else {
parent.right = newNode;
}
}
//删除
public void delete(int key) {
TreeNode cur = root;
TreeNode parent = null;
while (cur != null) {
if (key > cur.val) {
parent = cur;
cur = cur.right;
} else if (key < cur.val) {
parent = cur;
cur = cur.left;
} else {
//删除结点
remove(parent, cur);
return;
}
}
}
// 分情况讨论
private void remove(TreeNode parent, TreeNode del) {
//情况1:del.left==null
if (del.left == null) {
//情况1.1 del是root
if (del == root) {
root = del.right;
} else {
if (del == parent.left) {
//情况1.2 del不是root,del是parent.left
parent.left = del.right;
} else if (del == parent.right) {
//情况1.3 del不是root,del是parent.right
parent.right = del.right;
}
}
} else if (del.right == null) {
//情况2:del.right==null
if (del == root) {
//情况2.1 del是root
root = del.left;
} else {
if (del == parent.left) {
//情况2.2 del是parent.left
parent.left = del.left;
} else if (del == parent.right) {
//情况2.3 del是parent.right
parent.right = del.left;
}
}
} else {
//情况3 del.left和del.right都不为空
//将del右树的值最小的结点或者左树的值最大的结点和del替换
//右边找
TreeNode target = del.right;
TreeNode targetP = del;
while (target.left != null) {
targetP = target;
target = target.left;
}
//删除之前先交换
del.val = target.val;
//分情况删除
if (target == targetP.right) {
targetP.right = target.right;
}
if (target == targetP.left) {
targetP.left = target.right;
}
}
}
}