难度:中等
分类:二叉树
难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。
给定一个二叉搜索树的根节点root和一个值ky,删除二叉搜索树中的key对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
示例1:
输入:root=[5,3,6,2,4,null,7],key=3
输出:[5,4,6,2,null,null,7]
解释:给定需要删除的节点值是3,所以我们首先找到3这个节点,然后删除它。
一个正确的答案是[5,4,6,2,null,nul,7]
示例2:
输入:root=[5,3,6,2,4,null,7],key=0
输出:[5,3,6,2,4,nu,7]
解释:二叉树不包含值为0的节点
为了执行删除操作,我们需要遵循以下步骤:
key
的节点。key
的节点,则不需要删除操作,直接返回根节点。nullptr
。假设有以下的二叉搜索树:
5
/ \
3 6
/ \ \
2 4 7
我们想要删除值为 3 的节点。因此:
初始化和调用函数: 主程序创建了上述的二叉搜索树,并且呼叫了 deleteNode()
函数,命令它删除值为 3 的节点。
开始查找要删除的节点: deleteNode()
函数开始在树中递归搜索值为 3 的节点。
找到要删除的节点: 节点 3 被找到了,由于它有两个子节点,我们必须采取特殊步骤去删除它。
替代和删除:
5
/ \
4 6
/ \ \
2 4 7
5
/ \
4 6
/ \
2 7
调整树结构:
5
/ \
4 6
/ \
2 7
进行确认: 主程序中,我们再次通过中序遍历来确认树的结构。
程序结束: 树已更新,程序也随之结束。
删除二叉搜索树(BST)中的节点需要考虑保持BST的特性,即对于任何节点,其左子树中的所有节点都比它小,右子树中的所有节点都比它大。对于删除操作,通常有三种情况需要处理:
删除没有子节点的节点:这是最简单的情况,可以直接将该节点移除,然后将其父节点对应的指针置为 null。
删除有一个子节点的节点:在这种情况下,需要删除节点,并将其子节点连接到该节点的父节点上。这样可以保证BST的特性不被破坏。
删除有两个子节点的节点:这是最复杂的情况,需要更多步骤来确保树的完整性。我们通常采用以下方法:
删除过程中替换继承者的原因是我们希望删除操作之后BST的特性依然被保留。后继是右子树中最小的节点,它满足在左子树中的任何节点的值都比它小,在右子树中的任何节点的值都比它大的条件。当我们用后继替换掉要删除的节点后,就可以保证整个树仍然保持BST的所有特性,进行中序遍历时节点的值仍然是有序的。
这样操作能确保二叉搜索树在删除节点后仍然是有效的,即保持了二叉搜索树中序遍历结果为有序序列的特点。
#include // 包含输入输出流库
using namespace std; // 使用标准命名空间
// 定义二叉树节点结构
struct TreeNode {
int val; // 节点值
TreeNode *left; // 左子节点指针
TreeNode *right; // 右子节点指针
// 初始化构造函数
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
// 删除节点函数定义
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return root; // 如果节点为空,则直接返回
if (key < root->val) { // 如果要删除的值小于根节点的值,则在左子树中删除
root->left = deleteNode(root->left, key);
} else if (key > root->val) { // 如果要删除的值大于根节点的值,则在右子树中删除
root->right = deleteNode(root->right, key);
} else { // 找到要删除的节点
// 如果节点同时拥有左右子节点
if (root->left && root->right) {
TreeNode* temp = root->right;
while (temp->left) temp = temp->left; // 找到右子树中最小的节点
root->val = temp->val; // 将该节点的值赋给根节点
root->right = deleteNode(root->right, temp->val); // 删除右子树中的最小节点
} else { // 节点最多只有一个子节点
TreeNode* temp = root->left ? root->left : root->right; // 获得非空的子节点(如果有的话)
delete root; // 删除当前节点
root = temp; // 用非空的子节点替换当前节点
}
}
return root; // 返回修改后的树的根节点
}
// 中序遍历辅助函数定义
void inorderTraversal(TreeNode* root) {
if (root) { // 如果节点非空
inorderTraversal(root->left); // 遍历左子树
cout << root->val << " "; // 访问当前节点,打印节点值
inorderTraversal(root->right); // 遍历右子树
}
}
// 主函数
int main() {
// 创建并初始化一个 BST
TreeNode* root = new TreeNode(5); // 根节点值为 5
root->left = new TreeNode(3); // 根节点左子节点的值为 3
root->right = new TreeNode(6); // 根节点右子节点的值为 6
root->left->left = new TreeNode(2); // 左子节点的左子节点的值为 2
root->left->right = new TreeNode(4); // 左子节点的右子节点的值为 4
root->right->right = new TreeNode(7); // 右子节点的右子节点的值为 7
// 打印初始 BST
cout << "Initial BST (inorder traversal): ";
inorderTraversal(root); // 以中序遍历方式打印
cout << endl;
int key = 3; // 要删除的节点值
root = deleteNode(root, key); // 调用删除函数
// 打印删除特定节点后的 BST
cout << "BST after deleting node with key " << key << " (inorder traversal): ";
inorderTraversal(root); // 以中序遍历方式打印
cout << endl;
return 0; // 主函数正确结束返回 0
}