二叉排序树的定义:
二叉排序树(Binary Search Tree,BST)是一种二叉树,其中每个节点的值大于其左子树中任意节点的值,小于其右子树中任意节点的值。换句话说,对二叉排序树进行中序遍历时,节点的值是按照升序排列的。
二叉排序树具有以下特点:
- 左子树中的所有节点的值均小于根节点的值。
- 右子树中的所有节点的值均大于根节点的值。
- 左子树和右子树也分别是二叉排序树。
二叉排序树可以用于快速查找、插入和删除操作,时间复杂度为O(logn),其中n为树中节点的个数。如下图就是一个简单的二叉排序树:
二叉排序树的中序是一个严格递增序列(二叉排序树中不允许存在值相同的节点);
对于删除二叉排序树的节点,我们可以分情况讨论:
1.删除左子树为空的节点
如图我们要删除节点值为1的节点,它的左子树为空 , 这里我们使用链表来实现树,即节点包含 *left 、*right、val 这三个成员变量。
首先在删除 节点值为1的节点时 首先要找到它的父亲节点,即节点值为3的节点,我们将节点值为3的节点称为 A节点 ,节点值为1的节点称为 B节点。
然后我们直接让 A指向B的指针指向B节点的右子树即可!!! 本图就是 A的left 指向B的right;
A->left = B->right;
注意此处要判断 B 是 A 的左节点还是右节点。
2.删除右子树为空的节点
我们还是以删除 B节点为例 ,大致流程还是和上述删除左子树为空的节点相同,先找到 删除节点的父节点 A, 然后将 A指向B的指针指向B的左子树。此处仍要判断 B 是 A的左节点还是右节点
本图中: A->left = B->left;
3.删除叶子节点(即左右节点都为空)
叶子节点的左右节点都为空,和上述的 两个情况相同,故不考虑。
4.删除节点的左右节点都不为空
如下图:我们要删除 B 节点,我们此时是二叉树,直接删除节点并直接相连是不行的。我们此处采用 替换法 (即 寻找删除节点 B 的左子树的最大节点 或者 右子树的最小节点)
如图: B节点的左子树 包含节点 0和节点 1 (最大节点为 1) ,它的右子树包含节点 2(最小节点为2);
我们此处采用节点值为 0 的节点 C 替代。
找到 C 节点后将 要删除节点 B节点的值和 C节点的值替换,此时我们只要删除 C 节点即可!
在本图中,C 节点恰恰是 B的子节点,为了避免这种特例,我们将 C的父亲节点 定义为 D节点;
我们只要删除 C节点,由于我们寻找的是 B 的左节点的最大值,根据排序二叉树的性质(左小根,右大根),所以就一定表明了,C没有右节点!!!!
所以,我们仅仅让 D指向C的指针指向 C的左子树即可!注意要判断 C是D的左节点还是右节点,
本题中就是: D->left = C->left;
代码实现如下:其实并不难,只是要分类讨论:
此处代码实现删除左右子树都不为空的情况,采用 右子树最小节点替换方式
//搜索树不允许修改
//替换法: 找一个 节点的值 替代
//找 要删除节点的 左子树最大节点 或者 右子树的最小节点
bool Erase(const k& key)
{Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else//找到要删除节点{//进行删除操作if (cur->_left == nullptr)//左为空,父节点指向子节点右{if (cur == _root)//删除头结点{_root = cur->_right;}else{if (cur == parent->_left)//删除节点在父节点左parent->_left = cur->_right;elseparent->_right = cur->_right;}delete cur;}else if (cur->_right == nullptr)//右为空,找左{if (cur == _root)//删除头结点{_root = cur->_left;}else{if (cur == parent->_left)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}else // 左右子树都有,采用替换法{//找 右子树的最小节点Node* rightMin = cur->_right;Node* rightMinParent = cur;while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}swap(cur->_key, rightMin->_key);//判断 rightMin 是 rightMinPatent 的左右节点if (rightMinParent->_right == rightMin){rightMinParent->_right = rightMin->_right;}else{rightMinParent->_left = rightMin->_right;}delete rightMin;}return true;}}return false;
}
感谢大家看到这里,如果这篇文章对大家有一定的帮助,请大家点赞支持,如果还有一点模糊概念,可以写在评论区,我会顺着评论回答问题,最后祝大家学业有成,早日拿到心仪offer !!!