简介
本文将介绍如何从二叉查找树中删除某个任意的节点。由于二叉树特有的结构,即:
(1)所有左子树中的节点小于等于根节点
(2)所有右子树中的节点大于等于根节点
(3)对于任意节点满足(1)(2)
所以二叉查找树节点删除关键在于如何保证不破坏二叉查找树的性质。
问题分析
二叉查找树删除节点可以分成三种情况:
(1)删除叶子节点
叶子节点删除是最简单的情况,由于叶子节点没有左右子树,删除后不会破坏原有的树形结构,所以我们只需要找到节点并且把它置为null即可。
如图:
(2)被删除的节点只有一个子节点
比如我们要删除上图中3所在的节点,3只有一个左子树1。
实际上我们只需要把5所在节点的左子树指向原来3的左子树即可。
如图:
(3)被删除的节点左右子树都有
这种情况是比较复杂的,为了不破坏二叉查找书的结构,我们可以按照以下操作进行:
- 找出左子树中最大或者右子树中最小的值val
- 将当前节点的值替换为val
在左子树或者右子树中找到val删除
Note:
由于二叉查找树的性质,如果将当前节点替换为左子树中最大的或者右子树中最小的一定不会破坏二叉查找树的结构。
如图:
代码
public TreeNode deleteNode(TreeNode root, int key) {
if(root == null){
return root;
}
if(key < root.val){
root.left = deleteNode(root.left, key);
return root;
}
if(key > root.val){
root.right = deleteNode(root.right, key);
return root;
}
//开始执行删除操作
//(1)删除根节点
if(root.left == null && root.right == null){
root = null;
return root;
}
//(2)只有一个child,只有左子树
if(root.left == null && root.right != null){
root = root.right;
return root;
}
//(2)只有一个child,只有右子树
if(root.right == null && root.left != null){
root = root.left;
return root;
}
//(3)有两个child
if(root.left != null && root.right != null){
//挑选左子树中最大的或者右子树中最小的,替换当前节点,再将替换的节点置空
int val = findMaxInLeftTree(root.left);
root.val = val;
root.left = deleteNode(root.left, val);
return root;
}
return root;
}
//找到左子树中最大的值
private int findMaxInLeftTree(TreeNode left) {
if(left == null){
return 0;
}
if(left.right == null){
return left.val;
}
if(left.right == null && left.left == null){
return left.val;
}
return findMaxInLeftTree(left.right);
}
}