BST中删除某一元素对于是关于BST操作中最难的一部分了,想要深刻体会的小伙伴们可要下功夫了。
要想逐步的理解删除操作,那么应当先从一些比较特殊的例子开始:
一 、删除BST中的最小值
要想删除最小值,我们首先要找出最小值才可以,根据BST的特性可知,它的最小值一定位与最左下方的那个叶子结点处,查找最小值代码如下:
//查找二叉搜索树中最小值的非递归遍历
public E minimumNR() {
if(root == null)
return null;
TreeNode current = root;
while(current.left != null) {
current = current.left;
}
return current.element;
}
//递归遍历
public E minimum() {
if(size == 0)
return null;
return minimum(root).element;
}
//获取最小值所在的结点
private TreeNode minimum(TreeNode node) {
if(node.left == null) //node.left == null ,那么结点node即为最小结点
return node;
return minimum(node.left); //递归遍历
}
接下来执行删除操作:
//递归删除二叉搜索树中的最小值结点
public E deleteMin() {
E min = minimum();
root = deleteMin(root);
return min;
}
//返回删除最小值之后新的二叉树的根结点
private TreeNode deleteMin(TreeNode node) {
//递归结束判断
if(node.left == null) { //当前结点就是要删除的结点
node = node.right; //当前结点指向它的右子树结点,原来的node所指向的结点被抛弃
size--;
return node;
}
//递归
return deleteMin(node.left);
}
删除最大值的操作和删除最小值的操作类似,这里不再赘述。
删除操作会有三种情况:
1. 要删除的结点左孩子为空
2. 要删除的结点右孩子为空
3. 要删除的结点左右孩子均不为空
针对第三点,这里有两种选择策略
策略一: 用左子树的最大结点替换要删除的结点
策略二:用右子树的最小结点替换要删除的结点
非递归实现
//非递归实现,这里采用策略一
public boolean deleteNR(E e){
TreeNode current = root;
TreeNode parent = null;
//定位要删除的结点以及它的父结点的位置
while(current != null){
//要删除的结点在当前结点的左子树中
if(e.compareTo(current.element) < 0){
parent = current;
current = current.left;
}
//要删除的结点在当前结点的右子树中
else if(e.compareTo(current.element) > 0){
parent = current;
current = current.right;
}
//当前结点即是要删除的结点,定位成功
else{
break;
}
}
/*
*删除操作:考虑要删除的结点是否有左孩子
*1. 无左孩子:只需将当前结点的父结点和当前结点的子结点相连即可
*2. 有左孩子:找左子树中最大的结点,替换要删除的结点
*/
//树中没有要删除的结点
if(current == null){
return false;
}
//1. 无左孩子
if(current.left == null){
//根结点就是要删除的结点
if(parent == null){
root = current.right;
}
else{
if(e.compareTo(parent.element) < 0){
parent.left = current.right;
}
else{
parent.right = current.right;
}
}
}
//2. 有左孩子
else{
TreeNode parentOfRightMost = current;
TreeNode rightMost = current.left;
while(rightMost。right != null){
//找出左子树中最大的元素
parentOfRightMost = rightMost;
rightMost = rightMost.right;
}
//将左子树中最大结点元素值赋给要删除结点:即是把当前结点删除
//并用左子树中的最大结点替换当前结点
current.element = rightMost.element;
if(parentOfRightMost.right == rightMost)
parentOfRightMost.right = rightMost.left;
//要删除结点的左孩子结点没有右孩子结点
else
parentOfRightMost.left = rightMost.left;
}
size--;
return true;
}
递归实现
//删除二叉搜索树中的任意元素,并返回删除后的新树的根结点
public void delete(E element) {
root = delete(root,element);
}
private TreeNode delete(TreeNode node, E element) {
if(node == null)
return null;
if(element.compareTo(node.element) < 0) {
node.left = delete(node.left,element);
return node;
}
else if(element.compareTo(node.element) > 0) {
node.right = delete(node.right,element);
return node;
}
else {
//左子树为空
if(node.left == null) {
node = node.right;
size--;
return node;
}
//右子树为空
if(node.right == null) {
node = node.left;
size--;
return node;
}
//左右子树均不为空
/*这里有两种策略:
* 1. 用左子树中的最大结点替换当前结点
* 2. 用右子树中的最小结点替换当前结点
* 这里采用第二种
*/
TreeNode min = minimum(node.right);
TreeNode temp = new TreeNode(min.element);
node.right = deleteMin(node.right);
temp.left = node.left;
temp.right = node.right;
node = temp;
return temp;
}
}
二叉搜索树BST的学习至此结束,还会陆续更新其他博文,敬请期待!