二叉搜索樹---AVL樹刪除節點

前面我們寫了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的創建,這裏不加贅述;

發佈了109 篇原創文章 · 獲贊 17 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章