AVL平衡二叉樹

平衡二叉樹

二叉樹中全部結點的平衡因子BF的絕對值均小於等於1,即:\(|BF|\leq1\)。平衡因子是,結點的左子樹高度減去右子樹的高度。平衡因子BF絕對值大於1表示二叉樹失衡。ios

插入失衡

兩種狀況:c++

  1. 結點的平衡因子是1,向該結點的左子樹插入結點,該結點的平衡因子變爲2,致使失衡;
  2. 結點的平衡因子是-1,向該結點的右子樹插入結點,該結點的平衡因子變爲-2,致使失衡。

如何解決失衡?函數

關鍵問題是要找到失衡結點,離插入結點最近的失衡結點。this

失衡結點的特色:spa

  • 必定是插入結點的祖父結點
  • 插入結點時必定通過失衡結點

解決辦法:指針

採用遞歸的方法進行插入,插入成功後會進行回代,所以在回代的過程當中能夠判斷結點是否失衡,從而可以找到離插入結點最近的失衡結點。code

/*
一、判斷二叉樹是否失衡,若失衡返回true,不然返回false
二、若二叉樹失衡,則返回離插入結點最近的結點
*/
bool IsBalanced(BTNode<T> *&T,T key)
{
    if(!T)
    {
        //未找到值爲key的結點,進行插入
        Insert(key);
        return true;
    }
    else if(T->data==key)
    {
        return false;//找到結點key,不可插入
    }
    else if(T->data>key)
    {
        bool temp=IsBalanced(T->lchild,key);//若是temp爲真,則表示結點插入到T的左子樹
        if(temp)
        {
            //判斷T的平衡因子,若等於1,則須要調整
        }
    }
    else
    {
        //同上
    }
}

附上完整代碼:排序

#include <iostream>
using namespace std;

//結點結構
template <class T>
class BTNode
{
public:
    //結點數據
    T data;
    //左右孩子指針
    BTNode<T> *lchild, *rchild;
    //添加平衡因子
    int BF;

public:
    //構造函數
    BTNode(T D, int bf = 0, BTNode<T> *l = NULL, BTNode<T> *r = NULL) : data(D), BF(bf), lchild(l), rchild(r) {}
};

//AVL平衡二叉樹
template <class T>
class AVLTree
{
    //私有屬性
private:
    //二叉樹根節點
    BTNode<T> *root;

private:
    //銷燬二叉樹
    void Destory(BTNode<T> *&rt)
    {
        if(rt)
        {
            this->Destory(rt->lchild);
            this->Destory(rt->rchild);
            delete rt;
        }
    }
    //二叉樹查找
    //和二叉排序樹的查找方法同樣
    bool SearchAVL(BTNode<T> *rt, T key, BTNode<T> *&p, BTNode<T> *f = NULL)
    {
        if (!rt) //查找失敗,返回false
        {
            p = f; //p指向查找路徑上最後訪問的元素
            return false;
        }
        else if (rt->data == key) //查找成功,返回true
        {
            p = rt; //p指向查找到的元素
            return true;
        }
        else if (rt->data > key)
        {
            return this->SearchAVL(rt->lchild, key, p, rt);
        }
        else
        {
            return this->SearchAVL(rt->rchild, key, p, rt);
        }
    }
    //左旋處理
    void L_Rotate(BTNode<T> *&p)
    {
        BTNode<T> *R = p->rchild; //R指向p的左孩子
        p->rchild = R->lchild;    //p的右孩子指向R的左孩子
        R->lchild = p;            //R的左孩子指向p
        p = R;                    //該二叉樹的根節點變爲R
    }
    //右旋處理
    void R_Rotate(BTNode<T> *&p)
    {
        BTNode<T> *L = p->lchild;
        p->lchild = L->rchild;
        L->rchild = p;
        p = L;
    }
    //左平衡處理,已知結點的平衡因子是+2,所以一定是在該結點的左子樹插入的結點
    //二叉排序樹的根節點平衡因子的絕對值大於1,需進行平衡處理
    void LeftBalance(BTNode<T> *&p)
    {
        BTNode<T> *L = p->lchild; //L指向p的左孩子
        /*
        判斷L的平衡因子
        若平衡因子爲1,表示新節點插入在L的左子樹
        若平衡因子爲-1,表示新節點插入在L的右子樹
        */
        switch (L->BF)
        {
        case 1: //結點插入在L的左子樹,需進行右旋處理
            this->R_Rotate(p);
            p->BF = 0;
            p->rchild->BF = 0; //右旋處理後,需改變旋轉結點的平衡因子
            break;
        case -1:
        { //結點插入在L的右子樹,需進行雙旋處理
            BTNode<T> *L_R = L->rchild;
            switch (L_R->BF)
            {
            case 1: //結點插入在L_R的左子樹
                p->BF = -1;
                L->BF = 0;
                break;
            case 0: //結點L_R就是新插入的結點
                p->BF = 0;
                L->BF = 0;
                break;
            case -1: //結點插入在L_R的右子樹
                p->BF = 0;
                L->BF = 1;
                break;
            }
            L_R->BF = 0;
            this->L_Rotate(L); //先左旋處理
            this->R_Rotate(p); //後右旋處理
            break;
        }
        }
    }
    //右平衡處理,已知結點的平衡因子是-2,所以一定是在該結點的右子樹插入的結點
    void RightBalance(BTNode<T> *&p)
    {
        BTNode<T> *R = p->rchild;
        switch (R->BF)
        {
        case 1:
        { //新節點插入在R的左子樹上,需進行雙旋處理
            BTNode<T> *R_L = R->lchild;
            switch (R_L->BF)
            {
            case 1: //結點插入在R_L的左子樹上
                p->BF = 0;
                R->BF = -1;
                break;
            case 0: //R_L就是新插入的結點
                p->BF = 0;
                R->BF = 0;
                break;
            case -1: //結點插入在R_L的右子樹上
                p->BF = 1;
                R->BF = 0;
                break;
            }
            R_L->BF = 0;
            this->R_Rotate(R); //先右旋處理
            this->L_Rotate(p); //後左旋處理
            break;
        }
        case -1: //新節點插入在R的右子樹上,需進行左旋處理
            p->BF = 0;
            R->BF = 0;
            this->L_Rotate(p);
            break;
        }
    }
    //向二叉樹中插入結點,並保持平衡
    bool InsertAVL(BTNode<T> *&rt, T key, bool &taller) //taller用來記錄二叉樹是否長高
    {
        if (!rt) //表示未在二叉樹中找到結點值爲key的結點,需插入結點
        {
            rt = new BTNode<T>(key, 0, NULL, NULL); //將新節點賦值給rt指針
            taller = true;
            return true;
        }
        else if (rt->data == key) //存在key,返回false
        {
            taller = false;
            return false;
        }
        else if (rt->data > key)
        {
            if (!this->InsertAVL(rt->lchild, key, taller)) //未插入結點
            {
                return false;
            }
            if (taller) //二叉樹長高,表示遞歸回到rt結點
            {
                switch (rt->BF)
                {
                case 1: //結點rt的平衡因子爲1,而又在左子樹新插入結點,故結點rt失衡,需調整
                    this->LeftBalance(rt);
                    taller = false; //維護狀態,在失衡結點調整後,其祖父結點的平衡因子不會變,故不用更改,結束此模塊遞歸
                    break;
                case 0: //結點rt的平衡因子爲0,在左子樹插入結點,結點rt不會失衡,不用調整
                    rt->BF = 1;
                    taller = true; //插入新節點,二叉樹高度增長,繼續此模塊遞歸,找到失衡結點
                    break;
                case -1: //結點rt的平衡因子爲-1,在左子樹插入結點,結點rt不會失衡,不用調整
                    rt->BF = 0;
                    taller = false; //插入新節點,二叉樹高度未增,結束此模塊遞歸
                    break;
                }
            }
            return true;
        }
        else
        {
            if (!this->InsertAVL(rt->rchild, key, taller)) //未插入結點
            {
                return false;
            }
            if (taller) //二叉樹長高,表示遞歸回到rt結點
            {
                switch (rt->BF)
                {
                case 1: //結點rt的平衡因子爲1,而又在右子樹新插入結點,故結點rt不會失衡
                    rt->BF = 0;
                    taller = false; //插入新節點,二叉樹高度未增,結束此模塊遞歸
                    break;
                case 0: //結點rt的平衡因子爲0,在右子樹插入結點,結點rt不會失衡,不用調整
                    rt->BF = -1;
                    taller = true; //插入新節點,二叉樹高度增長,繼續此模塊遞歸,找到失衡結點
                    break;
                case -1: //結點rt的平衡因子爲-1,在右子樹插入結點,結點rt會失衡,用調整
                    this->RightBalance(rt);
                    taller = false; //維護狀態,在失衡結點調整後,其祖父結點的平衡因子不會變,故不用更改,結束此模塊遞歸
                    break;
                }
            }
            return true;
        }
    }
    //前序遍歷
    void PreOrder(BTNode<T> *rt)
    {
        if (rt)
        {
            cout << rt->data << " ";
            this->PreOrder(rt->lchild);
            this->PreOrder(rt->rchild);
        }
    }
    //中序遍歷
    void InOrder(BTNode<T> *rt)
    {
        if(rt)
        {
            this->InOrder(rt->lchild);
            cout<<rt->data<<" ";
            this->InOrder(rt->rchild);
        }
    }

public:
    //構造函數
    AVLTree() : root(NULL) {}
    //拷貝構造函數
    AVLTree(const AVLTree<T> &t) {}
    //銷燬二叉樹
    void Destory() 
    {
        this->Destory(this->root);
        this->root=NULL;
    }
    //析構函數
    ~AVLTree()
    {
        this->Destory(this->root);
    }
    //前序遍歷
    void PreOrder()
    {
        this->PreOrder(this->root);
    }
    //中序遍歷
    void InOrder()
    {
        this->InOrder(this->root);
    }
    //二叉樹查找
    bool Search(T key, BTNode<T> *&p = NULL)
    {
        return this->SearchAVL(this->root, key, p, NULL);
    }
    //插入操做
    bool Insert(T key)
    {
        bool p;
        return this->InsertAVL(this->root, key, p);
    }
};

int main()
{
    AVLTree<int> temp;
    for (int i = 0; i < 10; i++)
    {
        temp.Insert(i);
    }
    temp.PreOrder();
    cout<<endl;
    temp.InOrder();
    cout<<endl;

    system("pause");
    return 0;
}
相關文章
相關標籤/搜索