题意:
填写函数
void delete_avl_node( BTreeNode* root, int value );
移除AVL树上值为value的节点。
树和前几个题目一样,挂在根节点-1
的右子树下。
给你的树已经处于平衡状态,你不需要判断值是否有效,值一定存在。
思路:
①根据要删除的值,找到要删除的节点。
②分要删除的节点的左右儿子的情况来讨论。
③若左右儿子都有,则用以右儿子为根节点的树中的最小节点p来替代要删除的节点(或者用以左儿子为根节点的树中的最大的点p来替代要删除的节点),代替完了再把p删
④若只有一个儿子或者都没有,先用p记录下要删除的点,再用存在的左或右儿子代替,再将p删除即可。
⑤最后再判断根节点的平衡因子,更新高度即可。
源码:
#include <algorithm>
//
//struct BTreeNode{
// int value{0};
// int height{0};
// BTreeNode* parent{nullptr};
// BTreeNode* left_child{nullptr};
// BTreeNode* right_child{nullptr};
// BTreeNode( int value ){
// this->value = value;
// }
// BTreeNode(){
// this->value = 0;
// }
//};
int h(BTreeNode* node) { //获取高度函数
if (!node)
return 0;
else
return node->height;
}
void rotate_rr(BTreeNode* node) {
if (!node) return;
BTreeNode* t = node->right_child;
node->right_child = t->left_child;
if (t->left_child)
t->left_child->parent = node;
t->parent = node->parent;
if (t->parent)
if (t->parent->left_child == node)
t->parent->left_child = t;
else
t->parent->right_child = t;
node->parent = t;
t->left_child = node;
node->height = max(h(node->left_child), h(node->right_child)) + 1;
t->height = max(h(t->left_child), h(t->right_child)) + 1;
}
void rotate_ll(BTreeNode* node) {
if (!node) return;
BTreeNode* t = node->left_child;
node->left_child = t->right_child;
if (t->right_child)
t->right_child->parent = node;
t->parent = node->parent;
if (t->parent)
if (t->parent->left_child == node)
t->parent->left_child = t;
else
t->parent->right_child = t;
node->parent = t;
t->right_child = node;
node->height = max(h(node->left_child), h(node->right_child)) + 1;
t->height = max(h(t->left_child), h(t->right_child)) + 1;
}
void rotate_rl(BTreeNode* node) {
BTreeNode* t = node->right_child;
rotate_ll(t);
rotate_rr(node);
}
void rotate_lr(BTreeNode* node) {
BTreeNode* t = node->left_child;
rotate_rr(t);
rotate_ll(node);
}
BTreeNode* findMin(BTreeNode* p) { //找到最小点函数
while (p->left_child)
p = p->left_child;
return p;
}
BTreeNode* adjust(BTreeNode* node) {
if (h(node->left_child) - h(node->right_child) >= 2) { //如果树不平衡且左子树高,在此可判断出是l_型
if (h(node->left_child->left_child) > h(node->left_child->right_child)) //再通过左子树左右儿子高度差判断
rotate_ll(node);
else if (h(node->left_child->left_child) < h(node->left_child->right_child))
rotate_lr(node);
else
rotate_ll(node);
}
else if (h(node->right_child) - h(node->left_child) >= 2) { //如果不平衡且右子树高,在此可判断出是r_型
if (h(node->right_child->right_child) > h(node->right_child->left_child)) //再通过右子树左右儿子高度差判断
rotate_rr(node);
else if (h(node->right_child->right_child) < h(node->right_child->left_child))
rotate_rl(node);
else
rotate_rr(node);
}
return node;
}
BTreeNode* delete_avl_node1(BTreeNode* root, int value) {
if (root->value == -1) //从根节点传到右儿子
root = root->right_child;
if (value < root->value) //根据大小关系找到要删除的节点
root->left_child = delete_avl_node1(root->left_child, value);
else if (value > root->value)
root->right_child = delete_avl_node1(root->right_child, value);
//如果能到这步则说明找到了要删除节点的位置
else if (root->left_child && root->right_child) { //如果该节点左右都有儿子
BTreeNode* p = findMin(root->right_child); //用该点的右儿子的最小点p来代替该点
root->value = p->value;
root->right_child = delete_avl_node1(root->right_child, p->value); //删除节点p
}
else { //该点只有一个儿子或者都没有
BTreeNode* p = root;
if (!root->right_child) //如果该节点有右儿子
root = root->left_child;
else if (!root->left_child) //如果该节点有左儿子
root = root->right_child;
delete p;
}
if (root) { //检查当前root的是否平衡,因为是递推,所以会从下往上检查每个点是否平衡
root = adjust(root);
root->height = max(h(root->left_child), h(root->right_child)) + 1;
}
return root;
}
void delete_avl_node(BTreeNode* root, int value) {
root = delete_avl_node1(root, value);
}
ps:因为是递推,所以会从下往上每个点检查是否平衡。