資料結構與演算法——AVL樹類的C++實現

readyao發表於2016-04-08

關於AVL樹的簡介可以參考: 資料結構與演算法——AVL樹簡介

關於二叉搜尋樹(也稱為二叉查詢樹)可以參考:資料結構與演算法——二叉查詢樹類的C++實現

AVL-tree是一個"加上了額外平衡條件"的二叉搜尋樹,其平衡條件的建立是為了確保整棵樹的深度為O(logN)。要求任何節點的左右子樹高度相差最多1。


該AVL樹結點的資料結構:

struct AvlNode{
    Comparable element;
    AvlNode * left;
    AvlNode * right;
    int height;
    AvlNode(const Comparable & e, AvlNode * lt, AvlNode * rt, int h = 0):element(e), left(lt), right(rt), height(h){}
};
該結點資料結構其實是一個結點類。

該AVL樹的主要成員函式:

void makeEmpty();//清空該樹
bool isEmpty() const;//判斷該樹是否為空
void lessOrderPrintTree();//從小到大輸出該AVL平衡樹
void biggerOrderPrintTree();//從大到小輸出該AVL平衡樹
void insert(const Comparable & x);//插入值為x的結點
Comparable findMin() const;//找到最小值
Comparable findMax() const;//找到最大值

主要成員函式介紹:

/****************************************************************
*   函式名稱:void insert(const Comparable & x, AvlNode * t)
*   功能描述: 在結點t的後面插入值為x的結點 
*   引數列表: x為要插入結點的值 
*             t為當前的結點
*   返回結果:void 
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::insert(const Comparable & x, AvlNode * & t)
{
    if(t == NULL)//當前結點為空
        t = new AvlNode(x, NULL, NULL);
    else if(x < t->element){
        insert(x, t->left);
        if(height(t->left) - height(t->right) == 2){
            if(x < t->left->element)//單旋轉,左左插入
                rotateWithLeftChild(t);
            else
                doubleWithLeftChild(t);//雙旋轉,左右插入
        } 
    }
    else if(x > t->element){
        insert(x, t->right);
        if(height(t->right) - height(t->left) == 2){
            if(x > t->right->element)//單旋轉,右右插入
                rotateWithRightChild(t);
            else
                doubleWithRightChild(t);//雙旋轉,右左插入
        }
    }
    //如果x的值和當前結點的值相同,則忽略。也可以向之前二叉查詢樹一樣給每個結點再加一個num成員變數。
    t->height = max(height(t->left), height(t->right)) + 1;//更新結點t的高度
}

/****************************************************************
*   函式名稱:rotateWithLeftChild(AvlNode *t)
*   功能描述: 將當前結點進行單旋轉,用於左左插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::rotateWithLeftChild(AvlNode * & k2)
{
    cout << "左單旋轉" << endl;
    AvlNode * k1 = k2->left;
    k2->left = k1->right;
    k1->right = k2;

    k2->height = max(height(k2->left), height(k2->right)) + 1;
    k1->height = max(height(k1->left), k2->height) + 1;

    k2 = k1;
}
/****************************************************************
*   函式名稱:rotateWithRightChild(AvlNode *t)
*   功能描述: 將當前結點進行單旋轉,用於左右插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::rotateWithRightChild(AvlNode * & k1)
{
    cout << "右單旋轉" << endl;
    AvlNode * k2 = k1->right;
    k1->right = k2->left;
    k2->left = k1;

    k1->height = max(height(k1->left), height(k1->right)) + 1;
    k2->height = max(height(k2->right), k1->height) + 1;

    k1 = k2; 
}

/****************************************************************
*   函式名稱:doubleWithLeftChild(AvlNode *t)
*   功能描述: 將當前結點進行雙旋轉,用於左右插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::doubleWithLeftChild(AvlNode * & k3)
{
    cout << "**********************" << endl;
    cout << "左雙旋轉: " << endl;
    rotateWithRightChild(k3->left);
    rotateWithLeftChild(k3);
    cout << "**********************" << endl;
}

/****************************************************************
*   函式名稱:doubleWithRightChild(AvlNode *t)
*   功能描述: 將當前結點進行雙旋轉,用於右左插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::doubleWithRightChild(AvlNode * & k1)
{
    cout << "**********************" << endl;
    cout << "右雙旋轉: " << endl;
    rotateWithLeftChild(k1->right);
    rotateWithRightChild(k1);
    cout << "**********************" << endl;
}

關於右單旋轉的一個圖例:



結合圖形看該旋轉函式:
template<typename Comparable>
void AvlTree<Comparable>::rotateWithRightChild(AvlNode * & k1)
{
    cout << "右單旋轉" << endl;
    AvlNode * k2 = k1->right;
    k1->right = k2->left;
    k2->left = k1;

    k1->height = max(height(k1->left), height(k1->right)) + 1;
    k2->height = max(height(k2->right), k1->height) + 1;
    k1 = k2; 
}
左單旋轉是同樣的道理。

關於右雙旋轉的一個圖例:


結合圖形看該旋轉函式:
template<typename Comparable>
void AvlTree<Comparable>::doubleWithRightChild(AvlNode * & k1)
{
    cout << "**********************" << endl;
    cout << "右雙旋轉: " << endl;
    rotateWithLeftChild(k1->right);
    rotateWithRightChild(k1);
    cout << "**********************" << endl;
}

該函式中的註釋是為了測試該函式是否執行了。

下面給出一個完整的實測:

依次向樹中插入結點: 1, 2, 3, 4, 5, 6, 7, 16, 15。
先用圖示來表現一下具體的實現過程,然後用程式來驗證一下。在main函式的tree2樹就是用該資料序列生成的AVL樹,可以看列印資訊是否經過了相應的旋轉。



    AvlTree<int> tree2;
    
    cout << "構造AVL樹trre2: " << endl;
    for(int i = 1; i < 8; ++i)
        tree2.insert(i);
    tree2.insert(16);
    tree2.insert(15);

    tree2.lessOrderPrintTree();
    tree2.biggerOrderPrintTree();
輸出為:
構造AVL樹trre2: 
右單旋轉
右單旋轉
右單旋轉
右單旋轉
**********************
右雙旋轉: 
左單旋轉
右單旋轉
**********************
從小到大輸出:1 2 3 4 5 6 7 15 16 
從大到小輸出:16 15 7 6 5 4 3 2 1

下面是該AVL樹類的原始碼:


/*************************************************************************
	> File Name: AvlTree.cpp
	> Author: 
	> Mail: 
	> Created Time: 2016年04月08日 星期五 10時14分48秒
 ************************************************************************/

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

template<typename Comparable>
class AvlTree{
    public:
        AvlTree(){ root = NULL; }
        ~AvlTree();

        void makeEmpty();//清空該樹
        bool isEmpty() const;//判斷該樹是否為空
        void lessOrderPrintTree();//從小到大輸出該AVL平衡樹
        void biggerOrderPrintTree();//從大到小輸出該AVL平衡樹
        void insert(const Comparable & x);//插入值為x的結點
        Comparable findMin() const;//找到最小值
        Comparable findMax() const;//找到最大值

    private:
        struct AvlNode{
            Comparable element;
            AvlNode * left;
            AvlNode * right;
            int height;
            AvlNode(const Comparable & e, AvlNode * lt, AvlNode * rt, int h = 0):element(e), left(lt), right(rt), height(h){}
        };
        AvlNode * root;

    private:
        void makeEmpty(AvlNode * t);
        void lessOrderPrintTree(AvlNode * t);
        void biggerOrderPrintTree(AvlNode * t);
        int height(AvlNode * t) const;//獲得當前結點t的高度
        void insert(const Comparable & x, AvlNode * & t);//在t處,插入值為x的結點
        void rotateWithLeftChild(AvlNode * & k2);//單旋轉,左左插入的情況
        void rotateWithRightChild(AvlNode * & k1);//單旋轉,右右插入的情況
        void doubleWithLeftChild(AvlNode * & k3);//雙旋轉,左右插入的情況
        void doubleWithRightChild(AvlNode * & k1);//雙旋轉,右左插入的情況
        Comparable findMin(AvlNode * t) const;//找到最小值
        Comparable findMax(AvlNode * t) const;//找到最大值
};


/****************************************************************
*   函式名稱:findMax() 
*   功能描述: 找到該樹的最大值 
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
Comparable AvlTree<Comparable>::findMax() const
{
    if(!isEmpty())
        return findMax(root); 
}

/****************************************************************
*   函式名稱:findMax(AvlNode * t) 
*   功能描述: 找到該樹的最大值 
*   引數列表: t表示當前結點 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
Comparable AvlTree<Comparable>::findMax(AvlNode * t) const
{
    if(t->right== NULL)
        return t->element; 
    else 
        return findMax(t->right);

}

/****************************************************************
*   函式名稱:findMin() 
*   功能描述: 找到該樹的最小值 
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
Comparable AvlTree<Comparable>::findMin() const
{
    if(!isEmpty())
        return findMin(root); 
}

/****************************************************************
*   函式名稱:findMin(AvlNode * t) 
*   功能描述: 找到該樹的最小值 
*   引數列表: t表示當前結點 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
Comparable AvlTree<Comparable>::findMin(AvlNode * t) const
{
    if(t->left == NULL)
        return t->element; 
    else 
        return findMin(t->left);

}
/****************************************************************
*   函式名稱:~AvlTree()
*   功能描述: 解構函式,釋放結點記憶體空間 
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
AvlTree<Comparable>::~AvlTree()
{
    makeEmpty();
}
/****************************************************************
*   函式名稱:void insert(const Comparable & x)
*   功能描述: 插入值為x的結點 
*   引數列表: x為要插入結點的值 
*   返回結果:void 
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::insert(const Comparable & x)
{
    insert(x, root);
}

/****************************************************************
*   函式名稱:void insert(const Comparable & x, AvlNode * t)
*   功能描述: 在結點t的後面插入值為x的結點 
*   引數列表: x為要插入結點的值 
*             t為當前的結點
*   返回結果:void 
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::insert(const Comparable & x, AvlNode * & t)
{
    if(t == NULL)//當前結點為空
        t = new AvlNode(x, NULL, NULL);
    else if(x < t->element){
        insert(x, t->left);
        if(height(t->left) - height(t->right) == 2){
            if(x < t->left->element)//單旋轉,左左插入
                rotateWithLeftChild(t);
            else
                doubleWithLeftChild(t);//雙旋轉,左右插入
        } 
    }
    else if(x > t->element){
        insert(x, t->right);
        if(height(t->right) - height(t->left) == 2){
            if(x > t->right->element)//單旋轉,右右插入
                rotateWithRightChild(t);
            else
                doubleWithRightChild(t);//雙旋轉,右左插入
        }
    }
    //如果x的值和當前結點的值相同,則忽略。也可以向之前二叉查詢樹一樣給每個結點再加一個num成員變數。
    t->height = max(height(t->left), height(t->right)) + 1;//更新結點t的高度
}

/****************************************************************
*   函式名稱:rotateWithLeftChild(AvlNode *t)
*   功能描述: 將當前結點進行單旋轉,用於左左插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::rotateWithLeftChild(AvlNode * & k2)
{
    cout << "左單旋轉" << endl;
    AvlNode * k1 = k2->left;
    k2->left = k1->right;
    k1->right = k2;

    k2->height = max(height(k2->left), height(k2->right)) + 1;
    k1->height = max(height(k1->left), k2->height) + 1;

    k2 = k1;
}
/****************************************************************
*   函式名稱:rotateWithRightChild(AvlNode *t)
*   功能描述: 將當前結點進行單旋轉,用於左右插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::rotateWithRightChild(AvlNode * & k1)
{
    cout << "右單旋轉" << endl;
    AvlNode * k2 = k1->right;
    k1->right = k2->left;
    k2->left = k1;

    k1->height = max(height(k1->left), height(k1->right)) + 1;
    k2->height = max(height(k2->right), k1->height) + 1;

    k1 = k2; 
}

/****************************************************************
*   函式名稱:doubleWithLeftChild(AvlNode *t)
*   功能描述: 將當前結點進行雙旋轉,用於左右插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::doubleWithLeftChild(AvlNode * & k3)
{
    cout << "**********************" << endl;
    cout << "左雙旋轉: " << endl;
    rotateWithRightChild(k3->left);
    rotateWithLeftChild(k3);
    cout << "**********************" << endl;
}

/****************************************************************
*   函式名稱:doubleWithRightChild(AvlNode *t)
*   功能描述: 將當前結點進行雙旋轉,用於右左插入的時候 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::doubleWithRightChild(AvlNode * & k1)
{
    cout << "**********************" << endl;
    cout << "右雙旋轉: " << endl;
    rotateWithLeftChild(k1->right);
    rotateWithRightChild(k1);
    cout << "**********************" << endl;
}


/****************************************************************
*   函式名稱:int height(AvlNode *t) const
*   功能描述: 獲得當前結點t的高度 
*   引數列表: t是指向當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
int AvlTree<Comparable>::height(AvlNode * t) const
{
    return (t == NULL) ? -1 : t->height;
}


/****************************************************************
*   函式名稱:biggerOrderPrintTree()
*   功能描述: 按照從大到小的順序輸出該樹結點
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::biggerOrderPrintTree()
{
    cout << "從大到小輸出:";
    biggerOrderPrintTree(root); 
    cout << endl;
}
/****************************************************************
*   函式名稱:biggerOrderPrintTree(AvlNode * t)
*   功能描述: 按照從大到小的順序輸出該樹結點
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::biggerOrderPrintTree(AvlNode * t)
{
    if(t != NULL){
        biggerOrderPrintTree(t->right);
        cout << t->element << " ";
        biggerOrderPrintTree(t->left);
    } 
}

/****************************************************************
*   函式名稱:lessOrderPrintTree()
*   功能描述: 按照從小到大的順序輸出該樹結點
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::lessOrderPrintTree()
{
    cout << "從小到大輸出:";
    lessOrderPrintTree(root);    
    cout << endl;
}

/****************************************************************
*   函式名稱:lessOrderPrintTree()
*   功能描述: 按照從小到大的順序輸出該樹結點
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::lessOrderPrintTree(AvlNode * t)
{
    if(t != NULL){
        lessOrderPrintTree(t->left);
        cout << t->element << " ";
        lessOrderPrintTree(t->right);
    }
}

/****************************************************************
*   函式名稱:makeEmpty()
*   功能描述: 將該AVL平衡樹清空
*   引數列表: 無 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::makeEmpty()
{
   makeEmpty(root); 
}

/****************************************************************
*   函式名稱:makeEmpty(struct AvlNode * t)
*   功能描述: 釋放t指標指向的結點 
*   引數列表: t 當前結點的指標 
*   返回結果:無
*****************************************************************/
template<typename Comparable>
void AvlTree<Comparable>::makeEmpty(AvlNode * t)
{
    if(t != NULL){
        makeEmpty(t->left);
        makeEmpty(t->right);
        delete t;
    }
}

/****************************************************************
*   函式名稱:isEmpty()
*   功能描述: 判斷該樹是否為空 
*   引數列表: 無 
*   返回結果:如果為空則返回true;否則返回false;
*****************************************************************/
template<typename Comparable>
bool AvlTree<Comparable>::isEmpty() const
{
    return (root == NULL) ? true : false;
}


//測試主函式
int main()
{
    vector<int> v;
    AvlTree<int> tree;

    for(int i = 0; i < 10; i++)
        v.push_back(rand() % 10);

    cout << "v: ";
    for(int i = 0; i < 10; ++i)
        cout << v[i] << " ";
    cout << endl;

    cout << "構造AVL樹trre1: " << endl;

    for(int i = 0; i < 10; ++i)
        tree.insert(v[i]);
    tree.insert(13);
    tree.insert(12);
    tree.insert(11);

    tree.lessOrderPrintTree();        
    tree.biggerOrderPrintTree();


    AvlTree<int> tree2;
    
    cout << "構造AVL樹trre2: " << endl;
    for(int i = 1; i < 8; ++i)
        tree2.insert(i);
    tree2.insert(16);
    tree2.insert(15);

    tree2.lessOrderPrintTree();
    tree2.biggerOrderPrintTree();

    int min = tree2.findMin();
    cout << "min = " << min << endl;
    int max = tree2.findMax();
    cout << "max = " << max << endl;

    return 0;
}





相關文章