力扣:450. 删除二叉搜索树中的节点

题目描述

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

问题分析

递归法: 先递归找到节点,然后删除节点,删除节点比较复杂。
删除节点会遇到以下五种情况:
1.情况一:没找到删除节点,那么不对二叉树做任何处理,遍历到空节点直接返回
2.情况二:左右孩子都为空,即为叶子节点,直接删除节点
3.情况三:被删除节点的左孩子不为空,右孩子为空,删除节点,左孩子补位
4.情况四:被删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位
5.情况五:被删除节点左右孩子都不为空,将删除节点左子树放到删除节点的右子树的最左节点的左孩子上,然后右孩子补位。
迭代法: 要考虑如何删除节点,即要知道节点的父节点,将节点删除后,父节点要指向删除节点的孩子节点,其他逻辑是一样的。
做到这道题前最好先看:力扣:701. 二叉搜索树中的插入操作
要检验删除是否正确可以用二叉树层次遍历

代码实现

// 编程软件:VS2019
// 参考书籍:代码随想录
#include<iostream>
using namespace std;

// 定义二叉树
struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int v):val(v),left(nullptr),right(nullptr){}
};

/*
* 递归法:先递归找到节点,然后删除节点,删除节点比较复杂。
* 删除节点会遇到以下五种情况:
* 1.情况一:没找到删除节点,那么不对二叉树做任何处理,遍历到空节点直接返回
* 2.情况二:左右孩子都为空,即为叶子节点,直接删除节点
* 3.情况三:被删除节点的左孩子不为空,右孩子为空,删除节点,左孩子补位
* 4.情况四:被删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位
* 5.情况五:被删除节点左右孩子都不为空,将删除节点左子树放到删除节点的右子树的最左节点的左孩子上,然后右孩子补位
*/
TreeNode* deleteNode1(TreeNode* root, int key) {
	// 情况一:没找到删除的节点,遍历到空节点直接返回
	if (root == NULL) return root; // 注意这里要直接返回root
	// 找到节点
	if (root->val == key) {
		// 情况二:左右孩子都为空,即为叶子节点,直接删除节点
		if (root->left == NULL && root->right == NULL) {
			TreeNode* tmp = root; 
			delete tmp; // C++要注意释放内存
			return NULL; // 返回NULL
		}
		// 情况三:被删除节点的左孩子不为空,右孩子为空,删除节点,左孩子补位
		else if (root->left != NULL && root->right == NULL){
			TreeNode* tmp = root;
			root = root->left; 
			delete tmp; // C++要注意释放内存
			return root; // 返回左孩子
		}
		// 情况四:被删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位
		else if (root->left == NULL && root->right != NULL) {
			TreeNode* tmp = root;
			root = root->right;
			delete tmp; // C++要注意释放内存
			return root; // 返回右孩子
		}
		// 情况五:被删除节点左右孩子都不为空,将要删除节点的左子树放到删除节点的右子树的最左节点的左孩子上,然后右孩子补位
		else {
			TreeNode* cur = root->right;
			// 找到要删除节点的右子树的最左节点
			while (cur->left != NULL) {
				cur = cur->left;
			}
			cur->left = root->left;
			TreeNode* tmp = root;
			root = root->right;
			delete tmp; // C++要注意释放内存
			return root; // 返回右孩子
		}
	}
	if (key < root->val) root->left = deleteNode1(root->left, key); // 小于,往左子树
	if (key > root->val) root->right = deleteNode1(root->right, key); // 大于,往右子树
	return root; // 向上一层返回节点
}

/*
* 迭代法:要考虑如何删除节点,即要知道节点的父节点,将节点删除后,父节点要指向删除节点的孩子节点
* 其他逻辑是一样的。
*/ 
TreeNode* deleteNodeOperation(TreeNode* target) {
	if (target == NULL) return target; 
	// 情况二:左右孩子都为空,即为叶子节点,直接删除节点
	if (target->left == NULL && target->right == NULL) {
		TreeNode* tmp = target;
		delete tmp; // C++要注意释放内存
		return NULL; // 返回NULL
	}
	// 情况三:被删除节点的左孩子不为空,右孩子为空,删除节点,左孩子补位
	else if (target->left != NULL && target->right == NULL) {
		TreeNode* tmp = target;
		target = target->left;
		delete tmp; // C++要注意释放内存
		return target; // 返回左孩子
	}
	// 情况四:被删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位
	else if (target->left == NULL && target->right != NULL) {
		TreeNode* tmp = target;
		target = target->right;
		delete tmp; // C++要注意释放内存
		return target; // 返回右孩子
	}
	// 情况五:被删除节点左右孩子都不为空,将要删除节点的左子树放到删除节点的右子树的最左节点的左孩子上,然后右孩子补位
	else {
		TreeNode* cur = target->right;
		while (cur->left != NULL) {
			cur = cur->left;
		}
		cur->left = target->left;
		TreeNode* tmp = target;
		target = target->right;
		delete tmp; // C++要注意释放内存
		return target; // 返回右孩子
	}
}
TreeNode* deleteNode2(TreeNode* root, int key) {
	if (root == NULL) return NULL; 
	TreeNode* cur = root;
	TreeNode* pre = NULL; // 记录cur的父节点,用来删除cur
	while (cur) {
		if (cur->val == key) break; // 找到节点直接退出循环
		pre = cur;
		if (key < cur->val) cur = cur->left; // 小于,往左子树方向
		else cur = cur->right; // 大于,往右子树方向
	}
	if (pre == NULL) { //如果二叉搜索树只有根节点
		return deleteNodeOperation(cur);
	}
	if(cur==NULL) 
	// pre用于判断删除的节点是左孩子还是右孩子
	if (pre->left && pre->left->val==key) {
		pre->left = deleteNodeOperation(cur);
	}
	if (pre->right && pre->right->val == key) {
		pre->right = deleteNodeOperation(cur);
	}
	// 为什么这里没有情况一,因为没找到删除节点,也就是不对二叉树做任何处理,直接忽略
	return root;
}

int main() {
	TreeNode* root = new TreeNode(2);
	root->left = new TreeNode(1);
	root->right = new TreeNode(7);
	root->right->left = new TreeNode(5);
	root->right->right = new TreeNode(9);
	root->right->left->left = new TreeNode(4);
	root->right->left->right = new TreeNode(6);
	root->right->right->left = new TreeNode(8);
	root->right->right->right = new TreeNode(10);
	TreeNode* res = deleteNode2(root, 7);
	cout << res->val << endl;
}
// 结果:2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeKwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值