二叉排序树的节点插入和查找已经在本人的上一篇博文中讲解过了,大家可以参考:
https://blog.csdn.net/little_fire/article/details/80798663
本篇博文将为大家重点讲解一下二叉排序树的节点删除操作,对应的是leetcode的第450题目,希望为大家带来帮助。
首先,根据二叉排序树的性质可知,二叉排序树的待删除节点,可能存在以下三种情况:
(1)既包含左子树、又包含右子树;
(2)只包含左子树或只包含右子树;
(3)叶子节点;
其中后两种可以合并处理。
删除节点时,需要修改目标节点的父节点指针,因此,需要定义一个变量去保存一个父节点指针,删除操作就是要修改父节点指针。因此,重新定义节点查询函数BST_search,如下:
TreeNode* BST_search(TreeNode* node, int value, TreeNode* &parent) {
while (node) {
if (node->val == value){
break;
}
parent = node;
if (value < node->val)
{
node = node->left;
} else {
node = node->right;
}
}
return node;
}
对于(2)(3)两种情况,即目标节点只存在最多一个子树的情况,我们定一个删除节点的操作delete_node,需要传入待删除节点指针及其parent指针。
void delete_node(TreeNode* node, TreeNode* parent) {
if (node->val < parent->val) {
if (node->left) {
parent->left = node->left;
} else {
parent->left = node->right;
}
} else {
if (node->right) {
parent->right = node->right;
} else {
parent->right = node->left;
}
}
}
接下来,我们需要考虑情况(1),即包括左子树和右子树,此时需要获取目标节点的中序遍历后继节点,因为此时目标节点存在左子树,也存在右子树,后继节点即目标节点右子树的最左节点。函数如下:
TreeNode* find_successor(TreeNode* node, TreeNode* &parent) {
parent = node;
TreeNode* ptr = node->right;
while (ptr->left) {
parent = ptr;
ptr = ptr->left;
}
return ptr;
}
最后,我们就可以将整个程序整合一下,这里还需要考虑一下,当被删除节点是根节点(parent=NULL),且根节点只有至多一个子树的情况,此时,直接将root赋值给root存在的那个子树。若待删除节点不存在(未找到),直接返回root。整合后的代码如下:
TreeNode* BST_delete_node(TreeNode* root, int key) {
TreeNode* parent;
TreeNode* node = delete_node(root, key, parent);
if (!node) {
return root;
}
if (node->left && node->right) {
TreeNode* successor = find_successor(node, parent);
node->val = successor->val;
delete_node(successor, parent);
return root;
}
if (parent) {
delete_node(node, parent);
return root;
}
if (root->left) {
return root->left
} else {
return root->right;
}
}