平衡二叉樹(c++)實現(存在問題:插入節點后,問題:調整樹的結構存在問題)


!!版權聲明:本文為博主原創文章,版權歸原文作者和博客園共有,謝絕任何形式的 轉載!!

作者:mohist

 

更新那時間: 22:13  03-02-2020  邏輯存在問題:插入節點后,調整數的結構不正確。 待修復

 

 

------ 歡迎指正-------

1、參考資料:

  書籍:《算法導論》

  博文:http://www.cnblogs.com/fivestudy/fivestudy/p/10340647.html   原理講的很棒。有動畫,方便理解。

  這個網站可以清晰看清楚平衡二叉樹的插入刪除等詳細過程: https://www.cs.usfca.edu/~galles/visualization/AVLtree.html

 源碼:

#include <iostream>

using namespace std;



struct node 
{
    int data;
    int height;
    node *lc;
    node *rc;
    node()
        : data(0)
        , height(0)
        , lc(0)
        , rc(0)
    {

    }
};



// 平衡二叉樹
class avltree2
{
public:

    // 構造函數 
    avltree2()
        : root(NULL)
    {

    }

    virtual ~avltree2(){}
//---------------------------------------------------------

    // 返回結點的高度
    int height(node *pnode)
    {
        return pnode == NULL ? 0 : pnode->height;
    }

    // 計算兩個的最大值
    int max(int a, int b)
    {
        return a > b ? a : b;
    }

//------------------------------------------------------------
/*
    旋轉代碼:
        LL型
        RR型
        LR型
        RL型
*/ 

    // 左旋轉, 函數命名方式是以二叉樹插入結點的形狀命名的,這里的左旋,
    // 對應的形狀是 RR型,即在結點右孩子插入結點。
    node *rotate_rr(node *pnode)
    {
        node *ret_node = NULL;

        if (NULL != pnode)
        {
            // 保存失衡結點的右孩子
            node *loss_balance_node_rc = pnode->rc;

            // 將失衡結點的右孩子的左孩子賦值給失衡結點的右孩子
            pnode->rc   = loss_balance_node_rc->lc;

            // 將失衡結點作為失衡結點的左孩子
            loss_balance_node_rc->lc    = pnode;

            // 更新失衡結點與新根結點的高度
            pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1;
            loss_balance_node_rc->height = max( height( loss_balance_node_rc->lc), 
                                                height(loss_balance_node_rc->rc)) + 1;

            ret_node = loss_balance_node_rc;
        }

        return ret_node;
    }

    // 右旋, 函數名是以插入結點后的形式命名的,這里是
    // 將新結點插入后,形成LL形狀, 
    node *rotate_ll(node *pnode)
    {
        node *ret_node = NULL;

        if  (NULL != pnode)
        {
            node *loss_balance_node_lc    = pnode->lc;

            if (NULL != loss_balance_node_lc)
            {
                // 將失衡結點的左孩子的右孩子為失衡結點的左孩子
                pnode->lc = loss_balance_node_lc->rc;

                // 將失衡結點作為失衡結點左孩子的右孩子
                loss_balance_node_lc->rc    = pnode;

                // 更新高度
                pnode->height   = max(height(pnode->lc), height(pnode->rc)) + 1;

                loss_balance_node_lc->height = max( height(loss_balance_node_lc->lc),   
                                                    height(loss_balance_node_lc->rc)) + 1;
            }

            ret_node = loss_balance_node_lc;
        }

        return ret_node;
    }


    // LR 型
    // 函數命名方式同上, 需要先左旋在右旋
    node* rotate_lr(node *pnode)
    {
        if (NULL != pnode)
        {
            pnode->lc = rotate_rr(pnode->lc);
            
            pnode = rotate_ll(pnode);
        }

        return pnode;
    }

    // RL型
    // 同上,需要先右旋,再左旋
    node *rotate_rl(node *pnode)
    {
        if (NULL != pnode)
        {
            // 先右旋再左旋
            pnode->rc = rotate_ll(pnode->rc);

            pnode = rotate_rr(pnode);
        }
        
        return pnode;
    }

//------------------------------------------------------------

    

    // 計算pnode結點的平衡因子
    int get_balance_factor(node *pnode)
    {
        // 平衡因子= 左孩子 - 右孩子
        return (NULL == pnode) ? 0 : height(pnode->lc) - height(pnode->rc);
    }


    // 找到以pnode為根結點的最小結點
    node *get_min(node *pnode)
    {
        if (NULL == pnode)
            return pnode;

        while (pnode->lc)
            pnode = pnode->lc;
        
        return pnode;
    }

    // 找到以pnode為根結點的最大結點
    node *get_max(node *pnode)
    {
        if (NULL == pnode)
        {
            return pnode;
        }

        while (pnode->rc)
            pnode = pnode->rc;

        return pnode;
    }

    // 插入結點
    void insert(int key)
    {
        root = insert(root, key);
    }

    // 刪除結點值為key的結點
    void remove_node(int key)
    {
        if (NULL == root)
            return;

        // del_node(root, key);

        root = del_node2(root, key);
    }


    // 中序遍歷
    void in_order_traverse()
    {
        if (NULL == root)
            return;

        in_order(root);
    }

    // 刪除整棵樹
    void remove()
    {
        if (NULL == root)
            return;
        
        remove(root);
    }

    // 前序遍歷
    void pre_order_traverse()
    {
        if (NULL == root)
            return;

        pre_order(root);
    }



private:
    // 刪除所有結點
    void remove(node *pnode)
    {
        if (pnode)
        {
            remove(pnode->lc);
            remove(pnode->rc);
            delete pnode;
        }

        pnode = NULL;
    }

    // 前序遍歷
    void pre_order(node *pnode)
    {
        if (NULL != pnode)
        {
            cout << pnode->data << ", height = " << pnode->height << "  ";
            pre_order(pnode->lc);
            pre_order(pnode->rc);
        }
    } 

    // 中序遍歷
    void in_order(node *pnode)
    {
        if (NULL != pnode)
        {
            in_order(pnode->lc);
            cout << pnode->data << ", height = " << pnode->height << "  ";
            in_order(pnode->rc);    
        }
    }


    // 插入
    node* insert(node *pnode, int key)
    {

        // 為空,則創建結點
        if (NULL == pnode)
        {
            pnode = new(std::nothrow) node;
            if (NULL != pnode)
            {
                pnode->data = key;

                pnode->height = 1;
                return pnode;
            }
        }

        // 1、插入值比當前結點的值還要小,應該繼續找左子樹
        if (key < pnode->data)
        {
            pnode->lc = insert(pnode->lc, key);
        }
        // 2、比當前值大。應該繼續找當前結點的右子樹
        else if (key > pnode->data)
        {
            pnode->rc = insert(pnode->rc, key);
        }
        else 
        {
            // 3、相等,樹中已經存在插入的結點了,無法繼續插入相同結點
            return pnode;
        }

        // 4、更新結點的高度
        pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1;

        // 5、獲取插入后的平衡情況的平衡因子
        int pnode_bf     = get_balance_factor(pnode);

        // 6、下面開始判斷新插入節點的平衡因子,當前插入結果是否需要旋轉結點
        // 6.1 若為LL型,右旋
        if ( (1 < pnode_bf) && (key < pnode->data) )
            return rotate_ll(pnode);
        // 6.2 若為RR型,左旋
        if ( (-1 > pnode_bf) && (key > pnode->data) )
            return rotate_rr(pnode);
        // 6.3 若為LR型
        if ( (1 < pnode_bf) && (key > pnode->data) )
            return rotate_lr(pnode);
        // 6.4 若為RL型
        if ( (-1 > pnode_bf) && (key < pnode->data) )
            return rotate_rl(pnode);

        return pnode;
    }




    // 找到參數結點的父節點
    node *get_parent_node(node *pnode)
    {
        if (NULL == pnode)
        {
            return pnode;
        }

        node *parent_node = NULL;
        int key = pnode->data;
        
        node *cur_node = root;
        while (cur_node)
        {
            if (key == cur_node->data)
                break;
            else if (key < cur_node->data)
            {
                parent_node = cur_node;
                cur_node = cur_node->lc;
            }
            else if (key > cur_node->data)
            {
                parent_node = cur_node;
                cur_node = cur_node->rc;
            }
        }

        return parent_node;
    }


    // 刪除
    node *del_node2(node *pnode, int key)
    {
        if (NULL == pnode)
        {
            return pnode;
        }

        // 找 刪除結點的位置
        if (key < pnode->data)
        {
            pnode->lc = del_node2(pnode->lc, key);
        }
        else if (key > pnode->data)
        {
            pnode->rc = del_node2(pnode->rc, key);
        }
        else
        {
            // 找到刪除結點,

            // 3.1 若刪除結點同時存在左右孩子
            if ( (NULL != pnode->lc) && (NULL != pnode->rc) )
            {
                // 需要從左右子樹中最高的那棵樹開始刪除

                // 從左子樹中開始刪除
                if (height(pnode->lc) > height(pnode->rc))
                {
                    // 找到左子樹中最大的結點,替換當前結點
                    node *pre_node = get_max(pnode->lc);

                    // 將當前結點的值替換為前驅結點的值
                    pnode->data = pre_node->data;

                    // 刪除左子樹中最大的結點
                    pnode->lc = del_node2(pnode->lc, pnode->data);
                }

                // 刪除的結點從右子樹中開始找
                else
                {
                    // 找到后繼結點
                    node *successor_node = get_min(pnode->rc);

                    // 將刪除結點的值賦值給當前結點
                    pnode->data = successor_node->data;

                    // 刪除后繼結點中指定結點的值
                    pnode->rc = del_node2(pnode->rc, pnode->data);
                }
                
            }

            // 3.2 若只有左孩子
            else if ((NULL != pnode->lc) && (NULL == pnode->rc) )
            {
                // 指向需要刪除的結點
                node *del_node_tmp = pnode->lc;

                // 將孩子的值賦值給刪除結點
                pnode->data = del_node_tmp->data;
                // 將父節點指向孩子結點的分支設置為NULL
                pnode->lc = NULL;

                delete del_node_tmp;
                del_node_tmp = NULL;
            }
            // 3.3 若只有右孩子
            else if ( (NULL == pnode->lc) && (NULL != pnode->rc))
            {
                // 指向需要刪除的結點
                node *del_node_tmp = pnode->rc;
                pnode->data = del_node_tmp->data;
                // 將分支設置為NULL
                del_node_tmp->rc = NULL;

                delete del_node_tmp;
                del_node_tmp = NULL;
            }
            // 3.4 刪除的是葉子結點
            else
            {

                node *pnode_pa = get_parent_node(pnode);
                if (NULL != pnode_pa)
                {
                    if (pnode == pnode_pa->lc)
                        pnode_pa->lc = NULL;
                    else if (pnode == pnode_pa->rc)
                        pnode_pa->rc = NULL;
                }
                // 說明只有根結點
                else
                    root = NULL;
                    

                delete pnode;
                pnode = NULL;
            }
        }

        // 為了保證樹的平衡
        if (NULL == pnode)
            return pnode;

        // ------- 刪除節點后,需要做平衡
        pnode->height = max(height(pnode->lc), height(pnode->rc)) + 1;

        // 當前結點的平衡因子
        int pnode_bf    = get_balance_factor(pnode);

        // LL型
        if ( (1 < pnode_bf) && (0 <= get_balance_factor(pnode->lc)) )
        {
            return rotate_ll(pnode);
        }
        // LR型
        if ( (1 < pnode_bf) && (0 > get_balance_factor(pnode->lc)) )
        {
            return rotate_lr(pnode);
        }
        // RR型
        if ( (-1 > pnode_bf) && (0 >= get_balance_factor(pnode->rc)) )
        {
            return rotate_rr(pnode);
        }
        
        // RL型
        if ( (-1 > pnode_bf) && (0 < get_balance_factor(pnode->rc)) )
        {
            return rotate_rl(pnode);
        }

        return pnode;
    }


private:
    node *root;
};




int main()
{
    avltree2 tree;
    int insert_key = 0;
    cout << "插入開始,結束插入 輸入-1" << endl << endl << endl;
    while (1)
    {
        cout << "請輸入插入值:";
        cin >> insert_key;
        if (-1 == insert_key)
            break;
        tree.insert(insert_key);    
        cout << endl <<  "插入后,中序遍歷結果:";
        tree.in_order_traverse();

        cout << endl << endl;
    }

    cout << "前序遍歷:";
    tree.pre_order_traverse();
    cout << endl;

    cout << "========================================" << endl;
    cout << "開始刪除, 請輸入刪除元素的值, 結束輸入-1" << endl << endl;
    int del_key = 0;
    while (1)
    {
        cout << "請輸入刪除結點值: ";
        cin >> del_key;
        if (-1 == del_key)
            break;
    
        tree.remove_node(del_key);
        cout << "刪除后,中序遍歷:";
        tree.in_order_traverse();  
        cout << endl <<  "刪除后,前序遍歷:";
        tree.pre_order_traverse();
        cout << endl << endl;
    }


    cout << endl << endl << endl << "----------------------------" << endl << endl;
    cout << "刪除樹" << endl;
    tree.remove();


    return 0;
}
平衡二叉樹c++實現

 

2、結果:

      

3、GitHub 地址:https://github.com/mohistH/base_data_structure 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM