目录
🎈概念
🎈操作-查找
🎈操作-插入
🎈操作-删除(难点)
🎈概念
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
二叉搜索树 左<根<右
🎈操作-查找
我们根据上述的红色文字进行搜索查找。
public boolean search(int key) {
TreeNode cur = root;
while (cur != null) {
//如果值小于关键字,那么去二叉树的右边
if (cur.val < key) {
cur = cur.right;
//如果值大于关键字,那么去二叉树的左边
} else if (cur.val > key) {
cur = cur.left;
} else {
return true;
}
}
return false;
}
🎈操作-插入
思路:如果这个树是空树,我们就直接插入
如果这个树不是空树,按照查找的逻辑进行插入位置,插入新结点。
- 如果根节点==val 返回false
- 如果根节点< val 去cur左子树查找
- 如果根节点>val 去cur右子树查找
cur==null的时候,我们就要插入该节点(但是我们发现,如果遇到cur==null的时候,cur到了空的地方去,那谁记录cur的父节点呢?怎么给节点给cur所在位置呢?
我来用图给你们展示一下
此时我们通过cur=cur.left ,cur到了null的位置,然后我们要进行,插入值,该如何插入呢,此时我们就得给cur的父节点也记录下来,然后让node=parent.left。
/**
* 插入
*
* @param val
* @return true 表示插入成功, false 表示插入失败
*/
public boolean insert(int val) {
//如果是空树,那么就将val直接给根
if (root == null) {
root = new TreeNode(val);
return true;
}
TreeNode cur = root;
TreeNode parent = null;
while (cur != null) {
if (val < cur.val) {
parent = cur;
cur = cur.left;
} else if (val > cur.val) {
parent = cur;
cur = cur.right;
} else {
return false;
}
}
//上面并没有将新的节点插入进去
//我们看到上面不管是cur.right还是cur.left赋值给cur后,cur=null,此时的值并没有插入进行,而是判空结束了
TreeNode node = new TreeNode(val);
if (parent.val > val) {
//插入到左边
parent.left = node;
} else {
parent.right = node;
}
//我们看到parent的作用其实就是当cur==null的时候
//我们需要插入
return true;
}
🎈操作-删除(难点)
设待删除结点为 cur, 待删除结点的双亲结点为 parent
- 1. cur 是 root,则 root = cur.right
- 2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.right
- 3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.right
如果cur的左边空
cur在parent的左边,但是cur的左边空,那么我们将cur的右边节点给parent的左边
cur在parent的右边,但是cur的左边空,那么我们将cur的右边节点给parent的右边
(cur在parent的哪一边,就将cur左右哪一个不为空的节点给parent的哪一边)
- 1. cur 是 root,则 root = cur.left
- 2. cur 不是 root,cur 是 parent.left,则 parent.left = cur.left
- 3. cur 不是 root,cur 是 parent.right,则 parent.right = cur.left
cur左边为空,那么就将cur的左边节点 要么给parent的左边,那么parent的右边 //(取决于 cur在parent的哪一边)
- 1. 需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题
要么在左树中找到最大值(左数最右边的值),要么在右数找到最小值(右数最左边值)
我们最终的目的是让cur的右节点给cur,然后让cur指向cur的右树的最大值。
这种情况下我们就要将,6给cur,然后让原先6对应的值置空。
用tp记录cur的位置,然后t是tp的右孩子,为什么选择右孩子呢?因为我们要删除cur对应的值,那么我们就有俩种选择 (要么cur左边的最大值,要么cur右边的最小值)
此时我选择是找cur右边的最小值进行。
t是cur的右边,然后我们要先判断一下 是否t的左边为不为空,如果不为空,那么我们就要进入左边,因为二叉搜索树的特点就是 左孩子<根节点<右孩子,所以我们当初就是要找到cur的右边的最小值,就是一直往cur右孩子的左边找,不为空,那么我们就要将6赋值给cur,然后让置空即可。
如果下面还有值,如果右节点有值,那么就将那个右值赋值,如果左节点有值,那么就将左值赋值。
public void remove(int key){
//移除之前我们需要找到这个key
TreeNode cur = root;
TreeNode parent=cur;
while (cur != null) {
//如果值小于关键字,那么去二叉树的右边
if (cur.val < key) {
parent=cur;
cur = cur.right;
//如果值大于关键字,那么去二叉树的左边
} else if (cur.val > key) {
parent=cur;
cur = cur.left;
} else {
//开始删除
removeNode(cur,parent);
}
}
}
public void removeNode(TreeNode cur,TreeNode parent){
if(cur.left==null){
//左树空
if(cur==root){
root=cur.right;
} else if (cur==parent.left) {
parent.left=cur.right;
}else{
parent.right=cur.right;
}
//如果cur的左边空
//cur在parent的左边,但是cur的左边空,那么我们将cur的右边节点给parent的左边
//cur在parent的右边,但是cur的左边空,那么我们将cur的右边节点给parent的右边
//(cur在parent的哪一边,就将cur左右哪一个不为空的节点给parent的哪一边)
} else if (cur.right==null) {
//右数空
if(cur==root){
root=cur.left;
} else if (cur==parent.left) {
parent.left=cur.left;
}else {
parent.right=cur.left;
}
//cur左边为空,那么就将cur的左边节点 要么给parent的左边,那么parent的右边
//(取决于 cur在parent的哪一边)
} else {
//要么在左树中找到最大值(左数最右边的值)
//要么在右数找到最小值(右数最左边值)
//cur俩边都不为空
TreeNode tp=cur;
TreeNode t=cur.right;
//此时的cur'是关键字,cur的左右俩边都不为空,我们要将cur的右边值给到cur
// (cur右节点的左节点不为空,我们就将
if(t.left!=null){
tp=t;
t=t.left;
}
cur.val=t.val;
//删除t
//如果t在tp左边,将t的右边值给tp左边
//如果t在tp右边,将t的右边值给tp的右边
if(tp.left==t){
tp.left=t.right;
}else{
tp.right=t.right;
}
}
}
今天张老师生病了。