RBTree——紅黑樹

RBTree

RBTree:紅黑樹是一棵二叉搜索樹,它在每個節點上增加了一個存儲位來表示節點的顏色,可以是Red或Black。通過對任何一條從根到葉子簡單路徑上的顏色來約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,因而近似於平衡。


紅黑樹是平衡二叉搜索樹的一種(平衡二叉搜索樹中又有AVL Tree),滿足二叉搜索樹的條件外,還應買足下面的4個條件:
1. 每個節點不是紅色就是黑色;
2.根節點是黑色;
3.如果節點是紅,那麼子節點爲黑色;(所以新增節點的父節點爲黑色)
4.任一節點到NULL(樹尾端)的任何路徑,所含的黑節點數必須相同;(所以新增節點爲紅色)


ps: cur爲當前節點,p爲父節點,g爲祖父節點,u爲叔叔節點


第一種:cur爲紅,p爲紅,g爲黑,u存在且爲紅
則將p,u改爲黑,g改爲紅,然後把g當成cur,繼續向上調整。


這裏寫圖片描述


第二種:cur爲紅,p爲紅,g爲黑,u不存在/u爲黑,p爲g的左孩子,cur爲p的左孩子,則進行右單旋轉;相反,p爲g的右孩子,cur爲p的右孩子,則進行左單旋轉p、g變色–p變黑,g變紅


這裏寫圖片描述


第三種:cur爲紅,p爲紅,g爲黑,u不存在/u爲黑,p爲g的左孩子,cur爲p的右孩子,則針對p做左單旋轉;相反,p爲g的右孩子,cur爲p的左孩子,則針對p做右單旋轉則轉換成了情況2。


這裏寫圖片描述


RBTree和AVLTree的對比:
紅黑樹和AVL樹都是高效的平衡二叉樹,增刪查改的時間複雜度都是O(lg(N)),紅黑樹的不追求完全平衡,保證最長路徑不超過最短路徑的2倍,相對而言,降低了旋轉的要求,所以性能會優於AVL樹,所以實際運用中紅黑樹更多。


RBTree的應用:STL裏邊map和set,linux內核


#pragma once
#include <iostream>

using namespace std;
#include <stdio.h>

enum Colour
{
    RED,
    BLACK,
};

template<class K, class V>
struct RBTreeNode
{
    K _key;
    V _value;

    RBTreeNode<K, V>* _left;
    RBTreeNode<K, V>* _right;
    RBTreeNode<K, V>* _parent;

    Colour _colour; //類中枚舉

    RBTreeNode(const K& key, const V& value) //拷貝構造
        :_key(key)
        , _value(value)
        , _left(NULL)
        , _right(NULL)
        , _parent(NULL)
        , _colour(RED)
    {}
};

template<class K, class V>
struct RBTree
{
    typedef RBTreeNode<K, V> Node;
public:
    RBTree()
        :_root(NULL)
    {}

    bool Insert(const K& key, const V& value) //插入
    {
        if (_root == NULL)
        {
            _root = new Node(key, value);
            _root->_colour = BLACK;

            return true;
        }

        Node* parent = NULL;
        Node* cur = _root;
        while (cur)//從根開始遍歷
        {
            if (cur->_key < key)//插入值大於根 往右子樹遍歷
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key)//左
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }
        }
        // cur 即爲要插入的位置
        // parent 即爲原始葉子節點
        cur = new Node(key, value);
        cur->_colour = RED; // 插入的先預設爲紅 如果爲黑 對整個樹的影響過大

        //重建樹的鏈式結構
        if (parent->_key < key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }

        // 旋轉變化
        while (parent && parent->_colour == RED)
        {
            Node* grandfather = parent->_parent;
            if (parent == grandfather->_left) //左
            {
                Node* uncle = grandfather->_right; //由uncle決定怎麼變化

                // 1.存在且爲紅
                // 2.不存在,存在且爲黑
                if (uncle && uncle->_colour == RED)
                {
                    parent->_colour = uncle->_colour = BLACK;
                    grandfather->_colour = RED;

                    cur = grandfather;    // 往上推 看是否影響其他的節點
                    parent = cur->_parent;//
                }
                else 
                {
                    if (parent->_right == cur) //右邊 左右雙旋
                    {
                        RotateL(parent); //左旋

                        swap(cur, parent);
                    }

                    RotateR(grandfather); // 只右旋 一次
                    parent->_colour = BLACK;
                    grandfather->_colour = RED;
                }
            }
            else
            {
                Node* uncle = grandfather->_left;
                if (uncle && uncle->_colour == RED)
                {
                    parent->_colour = BLACK;
                    uncle->_colour = BLACK;
                    grandfather->_colour = RED;

                    // 繼續往上更新
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else // 不存在 / 存在且爲黑
                {
                    if (cur == parent->_left) // 左邊 右左雙旋
                    {
                        RotateR(parent);
                        swap(cur, parent);
                    }

                    RotateL(grandfather);// 右邊 只旋轉一次 左旋
                    parent->_colour = BLACK;
                    grandfather->_colour = RED;
                }
            }
        }

        _root->_colour = BLACK; //暴力格式化根爲黑

        return true;
    }

    void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        Node* ppNode = parent->_parent;

        parent->_left = subLR;
        if (subLR)
            subLR->_parent = parent;

        subL->_right = parent;
        parent->_parent = subL;

        if (_root == parent)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (ppNode->_right == parent)
            {
                ppNode->_right = subL;
            }
            else
            {
                ppNode->_left = subL;
            }

            subL->_parent = ppNode;
        }
    }


    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        Node* ppNode = parent->_parent;

        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;

        subR->_left = parent;
        parent->_parent = subR;

        if (parent == _root)
        {
            _root = subR;
            _root->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subR;
            }
            else
            {
                ppNode->_right = subR;
            }

            subR->_parent = ppNode;
        }

    }

    void InOrder()  //析構函數
    {
        _InOrder(_root);

    }

    void _InOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }

        _InOrder(root->_left);  
        cout << root->_key << " ";
        _InOrder(root->_right);
    }



    bool _IsBalance(Node* root, size_t blackNum, const size_t N)
    {
        if (root == NULL)
        {
            if (N != blackNum)
            {
                cout << "黑色節點的數量不相等" << endl;
                return false;
            }
            else
            {
                return true;
            }
        }

        if (root->_colour == BLACK)
        {
            ++blackNum;
        }

        if (root->_colour == RED
            && root->_parent->_colour == RED)
        {
            cout << "存在連續的紅節點" << _root->_key << endl;

            return false;
        }

        return _IsBalance(root->_left, blackNum, N)
            && _IsBalance(root->_right, blackNum, N);
    }

    bool IsBalance()
    {
        if (_root && _root->_colour == RED)
        {
            return false;
        }

        size_t N = 0;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_colour == BLACK)
            {
                ++N; //每條路徑上的黑色節點數相同 故只用求一次單鏈的黑色節點數
            }

            cur = cur->_left;
        }

        size_t blackNum = 0;
        return _IsBalance(_root, blackNum, N);
    }




private:
    Node* _root;
};

void TestRBTree()
{
    //int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    //RBTree<int, int> t;
    //for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    //{
    //  t.Insert(a[i], i);
    //}
    //t.InOrder();
    int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    RBTree<int, int> t;
    for (size_t i = 0; i < sizeof(a)/sizeof(a[0]); ++i)
    {
        t.Insert(a[i], i);
        cout<<a[i]<<"->IsBalance?"<<t.IsBalance()<<endl;
    }

    cout<<"IsBalance?"<<t.IsBalance()<<endl;
    t.InOrder();
}

AVLTree:https://blog.csdn.net/Romantic_C/article/details/81262703

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章