前面我們寫了AVL樹的創建AVL樹插入節點,即節點的插入,下面我們介紹AVL樹節點的刪除,與前面調整的 方法相同,在樹不平衡時,對樹進行調整,具體步驟如下:
1.
- 判斷樹是否爲NULL,若爲NULL,直接返回false;
- 判斷樹是否只有一個節點,且該節點爲要刪除的節點,直接刪除,_pRoot置NULL;
- 否則的話找到要刪除節點的位值,刪除該節點(分三種情況),並用其孩子節點來代替要刪除的節點,該過程樹可能出現不平衡,需要調整;
2.刪除節點:
- 當要刪除的節點只有左孩子;
- 要刪除的節點只有右孩子;
- 要刪除的節點左右孩子都存在,此時中序遍歷其右子樹的第一個節點,替換並刪除;
3.刪除後更新平衡因子,判斷樹是否平衡並做相應的旋轉處理
代碼實現:
bool _Remove(const k& key,const v& value)
{
if(_pRoot == NULL)
return false;
if(_pRoot->_pLeft == NULL && _pRoot->_pRight == NULL && _pRoot->_key == key)
{
delete _pRoot;
_pRoot = NULL;
}
//查找要刪除的位置
Node* pNode = _pRoot;
Node* pParent = NULL;
while(pNode)
{
if(pNode->_key > key)
{
pParent = pNode;
pNode = pNode->_pLeft;
}
else if(pNode->_key < key)
{
pParent = pNode;
pNode = pNode->_pRight;
}
else
break;
}
//已找到要刪除的節點
Node* pDel = NULL;
if(pNode)
{
if(pNode->_pLeft == NULL)//只有右子樹存在
{
if(_pRoot->_key == pNode->_key)
{
pDel = pNode;
_pRoot = pNode->_pRight;
delete pDel;
//刪除根節點不需要調整
return true;
}
else
{
if(pParent->_pLeft == pNode)
{
pDel = pNode;
pParent->_pLeft = pNode->_pRight;
pNode = pParent->_pLeft;
//更新平衡因子
//pParent->_bf++;
}
else
{
pDel = pNode;
pParent->_pRight = pNode->_pRight;
pNode = pParent->_pRight;
}
}
}
else if(pNode->_pRight == NULL)//只有左子樹
{
if(_pRoot == pNode)
{
pDel = pNode;
_pRoot = pNode->_pLeft;
delete pDel;
//刪除根節點不需要調整
return true;
}
else
{
if(pParent->_pLeft = pNode)
{
pDel = pNode;
pParent->_pLeft = pNode->_pLeft;
pNode = pParent->_pLeft;
}
else
{
pDel = pNode;
pParent->_pRight = pNode->_pLeft;
pNode = pParent->_pRight;
}
}
}
else //左右子樹都存在
{
Node* pCur = pNode;
while(pCur->_pLeft)
{
pParent = pCur;
pCur = pCur->_pLeft;//找到中序遍歷的第一個節點
}
pNode->_key = pCur->_key;
pNode->_value = pCur->_value;
pDel = pCur;//????
pParent->_pLeft = pCur->_pRight;
pNode = pParent->_pLeft;
}
delete pDel;
}
//刪除了節點pDel,更新平衡因子
while(pParent)
{
if(pParent->_pLeft == pNode)//刪除的是左孩子
pParent->_bf++;
else if(pParent->_pRight == pNode)//刪除的是右孩子
pParent->_bf--;
if(pParent->_bf == 1 || pParent->_bf == -1)//pParent左右孩子都存在,刪除節點不影響他的高度
return true;
else if(pParent->_bf == 0)
{
//if(pParent->_pLeft == pDel)//pParent存在左孩子
//{}
pNode = pParent;
pParent = pParent->_pParent;
}
else
{
//不滿足平衡樹,要做旋轉處理
if(pParent->_bf == 2)//右子樹
{
if(pNode==NULL ||pNode->_bf == 1)//右側
_RotateL(pParent);//左旋調整
else//左側
_RotateRL(pParent);//先右旋再左旋
}
else//左子樹
{
if(pNode==NULL || pNode->_bf == -1)//左側
_RotateR(pParent);
else//右側
_RotateLR(pParent);
}
break;//調整完後跳出循環
}
}
}
旋轉處理見上篇博客,AVL的創建,這裏不加贅述;