在上一篇文章里莫名其妙的说了AVL树的添加节点,那么这一次我们就可以简单的说一说AVL树的删除节点问题了。学会了添加,删除还会很难吗?当然很简单的,只需要先用递归找到那个需要删除的节点之后,如果其有左孩子,把自己删了然后拿左孩子顶替它,然后把左孩子的右孩子连向它的右孩子(我晕),如果其没有左孩子但是有右孩子,那就拿右孩子顶替他,如果它是个孤寡老人,那就不费事了,直接删了完事儿。
但是,真的有那么简单吗?很明显在删除完毕某些节点之后,需要判断树的深度是不是降低了,如果树的深度减少,那么整颗二叉树很可能再次出现不平衡的状态,需要进行调整。比如处于LH状态的一个节点的右子树的深度降低一层,其会处于LHLH的状态,则需要进行右旋以保证其平衡。所以我们把上一篇文章中的左旋和右旋操作的代码复制过来先(厚颜无耻脸)。
bool TurnLeft(TreeNode* &node) {
TreeNode* tempNode = node->rightChild;
node->rightChild = tempNode->leftChild;
tempNode->leftChild = node;
node = tempNode;
return true;
}
bool TurnRight(TreeNode* &node) {
TreeNode* tempNode = node->leftChild;
node->leftChild = tempNode->rightChild;
tempNode->rightChild = node;
node = tempNode;
return true;
}
bool BigTurnLeft(TreeNode* &node) {
TreeNode *nextNode = node->rightChild;
if (node->heightType != nextNode->heightType) {
node->rightChild = nextNode->leftChild;
node->rightChild->rightChild = nextNode;
nextNode->leftChild = nullptr;
}
TurnLeft(node);
return true;
}
bool BigTurnRight(TreeNode* &node) {
TreeNode *nextNode = node->rightChild;
if (node->heightType != nextNode->heightType) {
node->leftChild = nextNode->rightChild;
node->leftChild->leftChild = nextNode;
nextNode->rightChild = nullptr;
}
TurnRight(node);
return true;
}
在有了基础的旋转操作函数之后,我们就可以进行正式的删除操作了,我们还是从一个小例子入手看看我们要怎么进行删除操作。序列{33,17,42,8,3,19,42,39,60}已经构建出一棵AVL树,此时需要删除42这个节点,由于其同时具有左孩子和右孩子,所以用它的左孩子代替它,此时重新判断树的平衡性,发现替换的39处于RH的状态,但是仍保持平衡。
那么比如再删除一个19试一试,19是一个叶子节点,因此可以直接删除,但是在删除完毕后17的平衡性发生了变化,17原先处于LH的状态,在失去了其右孩子后,右子树的深度减小,其处于LHLH的状态,需要进行右旋操作以保证其平衡性。
在了解到基本的规则之后,那么我们就可以实现AVL树删除的代码了。
bool RemoveAVLTreeNode(TreeNode* &node, int value, bool &isShort) {
if (value == node->value) {
//若节点无左右孩子,则直接删除,深度-1
if (node->leftChild == nullptr && node->rightChild == nullptr) {
delete node;
node = nullptr;
isShort = true;
return true;
}
//若节点无左孩子但是有右孩子,用右孩子顶替该节点
if (node->leftChild == nullptr) {
TreeNode *tempNode = node;
node = node->rightChild;
delete tempNode;
isShort = true;
return true;
}
//若节点拥有左右孩子,则将左孩子的右孩子连向右孩子
TreeNode *tempNode = node;
node->leftChild->rightChild = node->rightChild;
node->leftChild->heightType = node->heightType;
node = node->leftChild;
switch (node->heightType)
{
case LEFTHEIGHT:
node->heightType = EQUALHEIGHT;
break;
case EQUALHEIGHT:
node->heightType = RIGHTHEIGHT;
break;
case RIGHTHEIGHT:
BigTurnLeft(node);
break;
default:
break;
}
delete tempNode;
isShort = true;
}
else if(value < node->value) {
//当数值小于该节点且该节点无左孩子时,表示无该数值,删除失败
if (node->leftChild == nullptr) {
return false;
}
if (RemoveAVLTreeNode(node->leftChild, value, isShort)) {
if (isShort) {
switch (node->heightType)
{
case LEFTHEIGHT:
node->heightType = EQUALHEIGHT;
break;
case RIGHTHEIGHT:
BigTurnLeft(node);
isShort = false;
break;
case EQUALHEIGHT:
node->heightType = RIGHTHEIGHT;
default:
break;
}
}
}
else {
return false;
}
}
else {
//当数值大于该节点且该节点无右孩子时,表示无该数值,删除失败
if (node->rightChild == nullptr) {
return false;
}
if (RemoveAVLTreeNode(node->rightChild, value, isShort)) {
if (isShort) {
switch (node->heightType)
{
case LEFTHEIGHT:
BigTurnLeft(node);
isShort = false;
break;
case RIGHTHEIGHT:
node->heightType = EQUALHEIGHT;
break;
case EQUALHEIGHT:
node->heightType = LEFTHEIGHT;
break;
default:
break;
}
}
}
else {
return false;
}
}
return true;
}