看过前面的AVL树的介绍和插入方法实现AVL树了解并简单实现-CSDN博客,接着可以来学习删除方法的实现
目录
1.AVL树的删除
2.平衡因子调节
3.删除代码逻辑
4.AVL树的整体代码
1.AVL树的删除
因为AVL树也是二叉搜索树,可按照二叉搜索树的方式将节点删除,然后再更新平衡因子,只不过与删除不同的时,删除节点后的平衡因子更新,最差情况下一直要调整到根节点的位置。
这里我们按照前面写过的二叉搜索树的删除的方法基础上进行AVL树的删除
- 对与删除节点有两个孩子,找它右子树最左结点,进行替换,就能转化为删除节点只有一个孩子或0个孩子的情况
- 删除节点有0个或1个孩子(这个我就不画图了,可以参考前面搜索二叉树删除画的图二叉搜索树了解和实现-CSDN博客)
现在最主要的是删除节点后,要进行调节平衡因子
2.平衡因子调节
(1)parent的平衡因子原来为0,在它的左子树或右子树被缩短后,则它的平衡因子改为1或-1。由于以 parent为根的子树高度没有改变,从parent到根结点的路径上所有结点都不需要调整。
(2)结点parent的平衡因子原不为0,且较高的子树被缩短,则parent的平衡因子变为0。以parent为根的子树高度减1,为此需要继续向上调整平衡因子。
(3)结点parent的平衡因子原为1/-1,且较矮的子树又被缩短,则在结点parent发生不平衡。为此需进行平衡化旋转来恢复平衡。
情况一:
情况一:通过一次单旋来恢复结点parent的平衡,由于旋转后以parent为根的子树的高度没有发生改变,此时就可不用再向上调整了。
情况二:
情况二:通过一次单旋来恢复结点parent的平衡,但由于旋转后以parent为根的子树的高度减一,此时就要再继续向上调整了。
情况三:
1)b==h-2,c==h-1,调整后的平衡因子:parent== -1,subRL=0,subR= 0
2) b==h-1,c==h-1,调整后的平衡因子:parent== 0,subRL=0,subR= 0
3) b==h-1,c==h-2,调整后的平衡因子:parent== 0,subRL=0,subR= 1
双旋后,这颗子树的高度减少了1,旋转完了还要继续向上调整平衡因子。
1)b==h-2,c==h-1,调整后的平衡因子:parent== 0,subRL=0,subR= -1
2) b==h-1,c==h-1,调整后的平衡因子:parent== 0,subRL=0,subR= 0
3) b==h-1,c==h-2,调整后的平衡因子:parent== 1,subRL=0,subR= 0
双旋后,这颗子树的高度减少了1,旋转完了还要继续向上调整平衡因子。
3.删除代码逻辑
bool erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < key){parent = cur;cur = cur->_right;}else if (cur->_kv.first > key){parent = cur;cur = cur->_left;}else // 找到结点进行删除{// 删除最右节点时,若最右节点父亲左为nullptr// 当删除最右结点后,最右结点父亲的右也为nullptr了,cur也为nullptr// 到时候判断cur为这个父结点的左还是右有问题,所以多加一个判断条件bool curIsParentLeft = false;Node* delNode = nullptr; // 处理要删除的结点// 0-1个孩子可以合在一起处理// 对于0个孩子的parent随便指向cur的左或右孩子// 对于1个孩子的,parent只能指向cur的左孩子或者右孩子if (cur->_left == nullptr) // (左孩子为空,右孩子不为空)||(左孩子和右孩子都为空)进入{if (parent == nullptr) // 要删除的结点为根结点 cur==_root{_root = cur->_right;}else{// 判断cur在parent的左还是右if (parent->_left == cur){parent->_left = cur->_right;curIsParentLeft = true;}else{parent->_right = cur->_right;curIsParentLeft = false;}}delNode = cur;cur = cur->_right;}else if (cur->_right == nullptr)// (左孩子不为空,右孩子为空)进入{if (parent == nullptr) // 要删除的结点为根结点 cur==_root{_root = cur->_left;}else{// 判断cur在parent的左还是右if (parent->_left == cur){parent->_left = cur->_left;curIsParentLeft = true;}else{parent->_right = cur->_left;curIsParentLeft = false;}}delNode = cur;cur = cur->_left;}else{// 2个孩子// 这里找右子树中最小的key替换Node* rightMinP = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinP = rightMin;rightMin = rightMin->_left;}// 找到进行替换cur->_kv = rightMin->_kv;// 判断rightMin在rightMinP的左还是右if (rightMinP->_left == rightMin){// rightMin左孩子不可能有,右孩子有或没有rightMinP->_left = rightMin->_right;curIsParentLeft = true;}else{rightMinP->_right = rightMin->_right;curIsParentLeft = false;}delNode = rightMin;parent = rightMinP;cur = rightMin->_right;}_upAdjust(parent, cur, curIsParentLeft);delete delNode; // 删除return true;}}return false;}
void _upAdjust(Node* parent,Node* cur,bool curIsParentLeft){//继续向上调整while (parent != NULL){if (cur == parent->_left && curIsParentLeft){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 1 || parent->_bf == -1){// 删除后高度不变break;}else if (parent->_bf == 0){// 往上更新cur = parent;parent = parent->_parent;if (parent != nullptr){if (parent->_left == cur){curIsParentLeft = true;}else{curIsParentLeft = false;}}}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == 2 && parent->_right->_bf == 0){// 左单旋_RotateL(parent);// 调整旋转后的平衡因子// 旋转后parent还是指向原来那个结点,只是位置换了parent->_bf = 1;parent->_parent->_bf = -1;// 旋转完了不需要往上更新平衡因子,旋转完后这课树原来高度==旋转高度break;}else if (parent->_bf == -2 && parent->_left->_bf == 0){// 右单旋_RotateR(parent);parent->_bf = -1;parent->_parent->_bf = 1;break;} // 剩下后面情况旋转后高度都变了(降低了1),所以要继续向上调整平衡因子else if (parent->_bf == 2 && parent->_right->_bf == 1){// 左单旋_RotateL(parent);parent->_bf = 0;parent->_parent->_bf = 0;// 继续向上调整平衡因子cur = parent->_parent;parent = cur->_parent;if (parent != nullptr){if (parent->_left == cur){curIsParentLeft = true;}else{curIsParentLeft = false;}}}else if (parent->_bf == -2 && parent->_left->_bf == -1){//右单旋_RotateR(parent);parent->_bf = 0;parent->_parent->_bf = 0;// 继续向上调整平衡因子cur = parent->_parent;parent = cur->_parent;if (parent != nullptr){if (parent->_left == cur){curIsParentLeft = true;}else{curIsParentLeft = false;}}}else if (parent->_bf == 2 && parent->_right->_bf == -1){// 右左双旋_RotateRL(parent);// 旋转完平衡因子修改和插入后平衡因子修改后的结果一样(这里不做修改了)// 继续向上调整平衡因子cur = parent->_parent;parent = cur->_parent;if (parent != nullptr){if (parent->_left == cur){curIsParentLeft = true;}else{curIsParentLeft = false;}}}else if (parent->_bf == -2 && parent->_left->_bf == 1){// 左右双旋_RotateLR(parent);// 旋转完平衡因子修改和插入后平衡因子修改后的结果一样(这里不做修改了)// 继续向上调整平衡因子cur = parent->_parent;parent = cur->_parent;if (parent != nullptr){if (parent->_left == cur){curIsParentLeft = true;}else{curIsParentLeft = false;}}}}else{// 前面出错了assert(false);}}}
4.AVL树的整体代码
AVL/AVL.h · wrf/C++test_cpp - Gitee.com