前言
最近在学习数据结构,学到了二叉搜索树节点的删除那里。左思右想除了老师写的用递归函数来实现,其他方法怎么实现二叉搜索树节点删除,思考了几天没头绪,无奈只能查查相关资料。
注:(原贴在这里20张图带你彻底搞懂二叉树的删除操作)本帖讲的是自己对原贴的重新理解,代码其实是一样的只是稍微做了修改。原贴使用的是JS,这里使用的是C/C++。如有冒犯请告知删除!
【想直接复制粘贴完整的二叉搜索树节点删除源码直接往下拉到底】
二叉搜索树删除节点思路
把将要删除的节点的值,与节点 root(根节点) 进行比较,若小于则去到左子树进行比较,若大于则去到右子树进行比较,重复以上操作直到找到一个节点的值等于删除的值,则将此节点删除。
如(图2)所示假设删除的是节点11,根节点是19,根节点19和根节点左子树上的右边的孩子节点11进行比较,若小于19则去根节点的左子树上找,找到了一个节点7,节点7又跟被删节点11进行比较……,直到找到的节点的值和删除节点的值相等为止。找根节点19右边子树上操作也是一样。
(为什么要这样操作呢?因为根据二叉搜索树的特性,若根节点的左子树不为空,根节点左边的孩子节点的值必须小于根节点的值,若根节点的右子树不为空,根节点右边的孩子节点的值必须大于根节点的值,如果有根节点的孩子的孩子节点,也就是孙子节点,同理也是一样的)
算法思路:因为要不断的寻找,这里可以使用一个while循环,将条件设成找到的节点不为空,不断的在左右子树上找被删节点的值,为空的话,就说明找到要删除的节点了。可以定义一个指针,开始指向根节点,每次while循环遍历,指向根节点的指针就指向它的左边的孩子节点或右边的孩子节点,直到找到被删的节点,然后就把这个指针赋值为NULL。
这里还要再定义个指针,指向被删节点的父节点,因为被删节点删除后,被删节点它如果有孩子节点的话,这个指针是要指向被删节点的孩子节点。同时再定义个bool类型,表示被删节点的父节点它是在左节点还是在右节点上,这点很重要下面会详说。最后别忘了开始分配的内存到最后一定要手动释放掉,不管是C还是C++,不考虑智能指针的话。
bool DeleteNode(Bnode* root, int key) {
if (!root || !key)return false;
Bnode* current = root;//当前节点,从根节点开始往下找
Bnode* current_parent = NULL; //当前节点的父节点
Bnode* delNode = NULL;//要删除的节点
bool isLeft = true;//记录最后是父节点的左还是右节点(true表示左,false表示右)
//寻找要删除的左子或右子节点
while (current) {
if (current->data == key) {
delNode = current;
current = NULL;
}
else if (current->data > key) {
//去当前节点的左子节点找
isLeft = true;
current_parent = current;
current = current->lchild;
}
else if (current->data < key) {
//去当前节点的右子节点找
isLeft = false;
current_parent = current;
current = current->rchild;
}
}
}
删除节点时有4种情况须分别处理:
1. 删除节点不存在左右子节点,即为叶子节点,直接删除
就是下面(图3)的情况
这个算法思路很简单就是判断被删节点它的左和右的孩子节点是否都为NULL,都为NULL表达它就是一个叶子节点。
还记得之前定义的bool类型嘛,前面只是简单的说了一下它的作用是找到被删节点的父节点是在左还是右,其实就是方便处理操作被删节点的后事和被删节点它下面的节点。通过bool类型的值,true或false就能很清楚的确定被删节点的父节点是在左边方向还是右边方向,假设如果删除的是叶子节点,我们只需通过bool类型的值,确定被删节点的父节点它的孩子节点方向把被删节点的父节点的左或右子节点赋值NULL就可以了,如果删除的不是叶子节点请看下面的第2种和3种情况。
//【1.如果删除的是叶子节点,即两端没有节点】
if (delNode->lchild == NULL &&
delNode->rchild == NULL) {
if (delNode == root) {
delete root;//如果开始就只有一个节点,即根节点,直接delete
}
else {
if (isLeft