算法導論13章之紅黑樹

  沒有三兩三,哪敢上梁山,在讀此篇以前,請保證基本的BST知識和紅黑樹的知識!html

  爲了保證對於規模爲n輸入的一些基本操做的複雜度在O(lgn)內,通常是創建平衡樹,通常的有AVL樹,2-3樹,2-3-4樹,跳躍表,固然通常效率很好的是紅黑樹,SGL STL 實現關聯容器就是使用的紅黑樹,也是基於效率的考慮。那到底什麼事紅黑樹呢?node

  首先介紹紅黑樹的結點,有color、key、parent、left、right五個域,其中color表示樹結點的顏色(有紅、黑兩種),其他四個域不言自明。ios

紅黑樹是知足一下5條紅黑性質的BST樹:ide

①  全部的結點或者是紅色的,或者是黑色的;spa

②  根節點是黑色的;3d

③  葉子結點(又稱外部結點,用NIL表示)是黑色的;code

④  若是一個結點是紅色結點,其左右子節點都是黑色結點;htm

⑤  對於紅黑樹的任意一個結點,其到它的全部子節點的簡單路徑上有相同的黑色結點(即有相同的黑高)。blog

這樣一棵紅黑樹保證沒有一條路徑的長度是任何其餘路徑的長度的兩倍,所以基本上時平衡的。element

由於對於規模爲n的輸入來講,紅黑樹的高度h<=2log(n+1), 下面給出一個簡單的證實:

  這也是本文的第一個要點,對於以下的一棵紅黑樹:

將紅色結點合併到黑色結點獲得以下所示的2-3-4平衡樹:

對於規模爲n的輸入,有n+1個葉子結點,設2-3-4樹的高度爲h1,則2h1<=n+1<=4h1,則h1<=lg(n+1);設原來的紅黑樹的高度爲h,有紅黑樹的性質剋制:紅黑樹中的紅色結點最多爲一半,即h<=2*(h1)<=2lg(n+1)。證畢。

 

本文的第二個要點是說明如何對插入操做進行修補,使之知足紅黑性質:

在開始以前,做爲預備知識,有:

A 互換父節點和其左子結點的顏色,而後以父節點進行右旋操做,整棵紅黑樹的紅黑性質不會被破壞,

B 互換父節點和其右子節點的顏色,而後以父節點進行左旋操做,整棵紅黑樹的紅黑性質不會被破壞。

C 每次插入結點的顏色爲紅色,這樣能夠保證性質5不會被破壞,而性質5一旦破壞時最男恢復的,只可能破壞性質2和性質4,而性質2和性質4的恢復相對簡單。

RB_INSERT_FIXUP的僞碼見書上315頁,此處再也不列出;對性質2的恢復只需設置T.root.color=BLACK便可恢復;對性質4的恢復只要待調整x結點的父節點的顏色變爲黑色即恢復了紅黑性質。那到底如何恢復性質4呢?

每次循環都將待調整結點向上調整直至父結點的顏色爲黑色,或者到了根結點則退出循環,再調整性質2便可。

根據x.p.p.left==x.p是否爲真分爲兩大類,而且這兩大類是對稱的。下面對一爲真的狀況給予說明:

此時又分爲3種狀況:

步驟(1)當前結點的叔結點都爲紅色(父結點顯然也爲紅色,不然已經知足紅黑性質了),此時只要將父結點和叔結點的顏色都變爲黑色,並將祖父結點由黑色變爲紅色,再將x結點「上溯」到其祖父結點(即x=x.p.p),如圖所示( 變換以前x指向N,變換以後x指向G):

通過這樣的變換,沒有破壞性質4,而且將x上移了兩層哦!

步驟(2)當前結點 x的叔結點的爲黑色結點,而且x爲其父結點的右子結點,此時令x結點(開始指向N)指向其父結點(x=x.p,調整以後指向P)並以x結點作左旋轉操做,轉換爲狀況(3),以下圖所示:

步驟(3)當前結點x的叔結點爲黑色結點,而且x爲其父結點的左子結點,此時互換x的父結點(圖中P)和x的祖父結點(圖中G)的顏色,並以祖父結點作右旋轉操做,此時已知足全部的紅黑性質(由預備知識點A)),退出循環。

對於初學者來講,可能不太明白爲何是這3步操做,還有這3步操做以前的關係。下面我一一道來:

其實最基本的思想是,咱們的操做盡量的不去破壞性質5,改成破壞性質4(也可能破壞其餘性質,但都很好恢復),而對於違背性質4的恢復手段來講,就是當前結點x,x的父節點,x的祖父結點,3個結點在一條線上,而不是「Z」型的,此時作預備知識點A或者預備知識點B的操做便可最終恢復性質4,因此會將步驟(2)轉換爲步驟(3)。對於考慮叔結點的緣由除了步驟(1)的很直觀的操做以外,就是若是叔結點爲紅色的話,不能進行步驟(3)的操做,由於操做以後G、U都爲紅色,從而破壞了性質4。

步驟(1)的複雜度爲O(lgh),步驟(2)、(3)的每一步的旋轉次數之多爲1,因此總的旋轉次數不超過2次,故RB_INSERT_FIXUP的複雜度爲O(lgn)。

 

本文的第三個要點講解對於刪除操做以後進行修補:

RB_DELETE_FIXUP操做的僞碼見185頁,此處再也不列出,根據x==x.p.left是否爲真分爲兩大類,一樣這兩大類是對稱的,下面覺得真的狀況進行說明:

爲了避免破壞性質5,進而選擇破壞性質一、性質二、性質4,因此選擇將刪除結點的黑色結點「下推」給待調整結點x,以此保持性質5不變;調整的主要任務就是去掉結點x的「下推的黑色」,這主要有兩種方法,

方法1、若是x的兄弟結點爲黑色(且該結點的兩個皆爲黑色結點),則將兄弟結點的顏色變爲紅色,這樣就去掉了「下推的黑色",而且x結點指向其父結點(x=x.p),以保持性質性質5,直到x爲根結點或者x的顏色爲紅色,此時只要簡單調整便可。

方法2、若是其兄弟結點爲黑色結點,且兄弟結點的右子節點爲紅色,此時,將x的父結點邊爲黑色,而且以父結點作左旋操做,使得通過x的結點的路徑多了一個黑色結點,正好去掉x」下推的黑色「,就已經知足性質2和性質4,退出循環便可。

因此按照此思路共有4中狀況:

步驟(1)x(圖中N)的兄弟結點(圖中S)爲紅色結點,互換父結點(圖中P)和兄弟結點的顏色,並以父結點作左旋轉操做(由預備知識點B),不會破壞紅黑性質,轉換爲步驟(2)、(3)、(4)的狀況,以下圖所示:

 

步驟(2)對應於方法1,x結點(圖中N),兄弟結點爲圖中S,操做完成以後x爲圖中P,以下圖所示:

步驟(3)x(圖中未畫出)的兄弟結點(圖中S)爲黑色結點,其左子結點(圖中SL)爲紅色,右子結點(圖中國SR)爲黑色,互換SL和S的顏色並以S作右旋轉操做,將狀況轉爲爲步驟(4),作轉換的緣由是,使得轉換後的S結點爲紅色,在步驟(4)調整爲黑色,用來彌補將兄弟結點變爲父結點顏色帶來的黑色結點減小,使得S所在簡單路徑上的黑色結點數不變,保持性質5.

步驟(4)到了終極解決方法了,對應於方法2,操做以下圖所示:

顯然步驟(2)的複雜度爲O(lgh),步驟(1)、(3)、(4)的每一步的調整最多一次,因此總共的調整次數不超過3次,RB_DELETE_FIXUP的複雜度爲O(lgn)。我想旋轉次數少,是能體現RB樹相較於AVL樹的優點的地方吧。

 

最後,貼出C++實現的代碼:

#include <iostream>
#include <stack>
using namespace std;


enum Color{RED=0,BLACK=1};

template<class T>
struct RedBlackTreeNode
{
    RedBlackTreeNode():color(BLACK),key(T()),parent(NULL),left(NULL),right(NULL){}
    int color;
    T key;
    RedBlackTreeNode<T>* parent;
    RedBlackTreeNode<T>* left;
    RedBlackTreeNode<T>* right;
};

template<class T>
class RedBlackTree
{
public:
    RedBlackTree(){root=NULL;};
    ~RedBlackTree(){};
    int get_maximum(T& ret) const;
    int get_minimum(T& ret) const;
    int get_successor(const T& k,T& ret) const;
    int get_predecessor(const T& k,T& ret) const;
    bool search_element(const T& k) const;
    int insert_key(const T& key);
    int delete_key(const T& key);
    RedBlackTreeNode<T>* get_root() const;
    void inorder_tree_walk() const;
private:
    RedBlackTreeNode<T>* root;
    static RedBlackTreeNode<T>* NIL;
    RedBlackTreeNode<T>* get_maximum(RedBlackTreeNode<T>* pnode) const;
    RedBlackTreeNode<T>* get_minimum(RedBlackTreeNode<T>* pnode) const;
    RedBlackTreeNode<T>* get_successor(RedBlackTreeNode<T>* pnode) const;
    RedBlackTreeNode<T>* get_predecessor(RedBlackTreeNode<T>* pnode) const;
    RedBlackTreeNode<T>* get_parent(RedBlackTreeNode<T>* pnode) const;
    RedBlackTreeNode<T>* get_left(RedBlackTreeNode<T>* pnode) const;
    RedBlackTreeNode<T>* get_right(RedBlackTreeNode<T>* pnode) const;
    int get_color(RedBlackTreeNode<T>* pnode) const;
    void set_color(RedBlackTreeNode<T>* pnode,const int& color);
    void left_rotate(RedBlackTreeNode<T>* pnode);
    void right_rotate(RedBlackTreeNode<T>* pnode);
    void rb_insert_fixup(RedBlackTreeNode<T>* pnode);
    void rb_delete_fixup(RedBlackTreeNode<T>* pnode);
    void rb_transplant(RedBlackTreeNode<T>* oldnode,RedBlackTreeNode<T>* newnode);
    RedBlackTreeNode<T>* search_tree_node(const T& k) const;
    int get_key(RedBlackTreeNode<T>* pnode) const;
    void make_empty(RedBlackTreeNode<T>* root);
};

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_root() const
{
    return root;
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::NIL=new RedBlackTreeNode<T>();

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_maximum(RedBlackTreeNode<T>* pnode) const
{
    while(pnode->right!=NIL)
        pnode=pnode->right;
    return pnode;
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_minimum(RedBlackTreeNode<T>* pnode) const
{
    while(pnode->left!=NIL)
        pnode=pnode->left;
    return pnode;
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_parent(RedBlackTreeNode<T>* pnode) const
{
    return pnode->parent;
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_left(RedBlackTreeNode<T>* pnode) const
{
    return pnode->left;
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_right(RedBlackTreeNode<T>* pnode) const
{
    return pnode->right;
}

template<class T>
int RedBlackTree<T>::get_color(RedBlackTreeNode<T>* pnode) const 
{
    return pnode->color;
}

template<class T>
void RedBlackTree<T>::set_color(RedBlackTreeNode<T>* pnode,const int& color)
{
    pnode->color=color;
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_successor(RedBlackTreeNode<T>* pnode) const
{
    if(pnode->right!=NIL)
        return get_minimum(pnode->right);
    else
    {
        RedBlackTreeNode<T>* parentnode=get_parent(pnode);
        while(parentnode!=NIL&&pnode==parentnode->right)
        {
            pnode=parentnode;
            parentnode=get_parent(pnode);
        }
        return parentnode;
    }
}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::get_predecessor(RedBlackTreeNode<T>* pnode) const
{
    if(pnode->left!=NIL)
        return get_maximum(pnode->left);
    else
    {
        RedBlackTreeNode<T>* parentnode=get_parent(pnode);
        while(parentnode!=NIL&&pnode==parentnode->left)
        {
            pnode=parentnode;
            parentnode=get_parent(pnode);
        }
        return parentnode;
    }
}

template<class T>
void RedBlackTree<T>::left_rotate(RedBlackTreeNode<T>* pnode)
{
    RedBlackTreeNode<T>* rightnode=get_right(pnode);
    pnode->right=rightnode->left;
    if(rightnode->left!=NIL)
        rightnode->left->parent=pnode;
    rightnode->parent=pnode->parent;
    if(pnode->parent==NIL)
        root=rightnode;
    else if(pnode==pnode->parent->left)
        pnode->parent->left=rightnode;
    else 
        pnode->parent->right=rightnode;
    rightnode->left=pnode;
    pnode->parent=rightnode;
}

template<class T>
void RedBlackTree<T>::right_rotate(RedBlackTreeNode<T>* pnode)
{
    RedBlackTreeNode<T>* leftnode=pnode->left;
    pnode->left=leftnode->right;
    if(leftnode->right!=NIL)
        leftnode->right->parent=pnode;
    leftnode->parent=pnode->parent;
    if(pnode->parent==NIL)
        root=leftnode;
    else if(pnode==pnode->parent->left)
        pnode->parent->left=leftnode;
    else
        pnode->parent->right=leftnode;
    leftnode->right=pnode;
    pnode->parent=leftnode;
}

template<class T>
void RedBlackTree<T>::rb_insert_fixup(RedBlackTreeNode<T>* pnode)
{
    RedBlackTreeNode<T>* gpnode,*unclenode;//祖父grandparent結點和叔uncle結點
    while(get_color(get_parent(pnode))==RED)
    {
        gpnode=get_parent(get_parent(pnode));
        if(get_left(gpnode)==get_parent(pnode))  //category A
        {
            unclenode=get_right(gpnode);
            if(get_color(unclenode)==RED)   //case 1
            {
                set_color(gpnode,RED);
                set_color(unclenode,BLACK);
                set_color(get_parent(pnode),BLACK);
                pnode=gpnode;
            }
            else
            {
                if(pnode==get_right(get_parent(pnode)))  //case 2
                {
                    pnode=get_parent(pnode);
                    left_rotate(pnode);
                }
                set_color(get_parent(pnode),BLACK);   //case 3
                set_color(get_parent(get_parent(pnode)),RED);
                right_rotate(get_parent(get_parent(pnode)));
            }
        }//category A
        else//category B
        {
            unclenode=get_left(gpnode);
            if(get_color(unclenode)==RED)//case 1
            {
                set_color(gpnode,RED);
                set_color(unclenode,BLACK);
                set_color(get_parent(pnode),BLACK);
                pnode=gpnode;
            }
            else
            {
                if(pnode==get_left(get_parent(pnode)))//case 2
                {
                    pnode=get_parent(pnode);
                    right_rotate(pnode);
                }
                set_color(get_parent(pnode),BLACK);//case 3
                set_color(get_parent(get_parent(pnode)),RED);
                right_rotate(get_parent(get_parent(pnode)));
            }
        }
    }
    root->color=BLACK;
}

template<class T>
void RedBlackTree<T>::rb_delete_fixup(RedBlackTreeNode<T>* pnode)
{
    RedBlackTreeNode<T>* brothernode;
    while(pnode!=root&&get_color(pnode)==BLACK)
    {
        if(get_left(get_parent(pnode))==pnode)             //category A
        {
            brothernode=get_right(get_parent(pnode));      
            if(get_color(brothernode)==RED)                //case f1
            {
                set_color(brothernode,BLACK);
                set_color(get_parent(pnode),RED);
                left_rotate(get_parent(pnode));
                brothernode=get_right(get_parent(pnode));
            }
            if(get_color(get_left(brothernode))==BLACK&&get_color(get_right(brothernode))==BLACK) //case 2
            {
                set_color(brothernode,RED);
                pnode=get_parent(pnode);
            }
            else
            {
                if(get_color(get_right(brothernode))==BLACK)   //case 3                            
                {
                    set_color(get_left(brothernode),BLACK);
                    set_color(brothernode,RED);
                    right_rotate(brothernode);
                    brothernode=get_right(get_parent(pnode));
                }

                set_color(brothernode,get_color(get_parent(pnode)));  //case 4
                set_color(get_parent(pnode),BLACK);
                set_color(get_right(brothernode),BLACK);
                left_rotate(get_parent(pnode));
                pnode=root;
            }
        }//category A
        else  //category B
        {
            brothernode=get_left(get_parent(pnode));
            if(get_color(brothernode)==RED)//case 1
            {
                set_color(brothernode,BLACK);
                set_color(get_parent(pnode),RED);
                right_rotate(get_parent(pnode));
                brothernode=get_left(get_parent(pnode));
            }
            if(get_color(get_left(brothernode))==BLACK&&get_color(get_right(brothernode))==BLACK)//case 2
            {
                set_color(brothernode,RED);
                pnode=get_parent(pnode);
            }
            else
            {
                if(get_color(get_left(brothernode))==BLACK)//case 3
                {
                    set_color(get_right(brothernode),BLACK);
                    set_color(brothernode,RED);
                    left_rotate(brothernode);
                    brothernode=get_left(get_parent(pnode));
                }
                set_color(brothernode,get_color(get_parent(pnode)));//case 4
                set_color(get_parent(pnode),BLACK);
                set_color(get_left(brothernode),BLACK);
                right_rotate(get_parent(pnode));
                pnode=root;
            }
        }
    }
    pnode->color=BLACK;
}

template<class T>
int RedBlackTree<T>::insert_key(const T& key)
{
    RedBlackTreeNode<T>* newnode=new RedBlackTreeNode<T>();
    newnode->key=key;
    newnode->color=RED;
    newnode->parent=NIL;
    newnode->left=NIL;
    newnode->right=NIL;
    if(NULL==root)
    {
        root=newnode;
    }
    else
    {
        RedBlackTreeNode<T>* tmpnode=root;
        RedBlackTreeNode<T>* parentnode;
        while(tmpnode!=NIL)
        {
            parentnode=tmpnode;
            if(newnode->key<tmpnode->key)
                tmpnode=tmpnode->left;
            else
                tmpnode=tmpnode->right;
        }
        newnode->parent=parentnode;
        if(newnode->key<parentnode->key)
            parentnode->left=newnode;
        else
            parentnode->right=newnode;
    }
    rb_insert_fixup(newnode);
    return 0;
}

template<class T>
void RedBlackTree<T>::rb_transplant(RedBlackTreeNode<T>* oldnode,RedBlackTreeNode<T>* newnode)
{
    if(get_parent(oldnode)==NIL)
        root=newnode;
    else if(oldnode==get_left(get_parent(oldnode)))
        oldnode->parent->left=newnode;
    else
        oldnode->parent->right=newnode;
    newnode->parent=oldnode->parent;

}

template<class T>
RedBlackTreeNode<T>* RedBlackTree<T>::search_tree_node(const T& k) const
{
    RedBlackTreeNode<T>* ptmpnode=root;
    while(ptmpnode!=NIL)
    {
        if(ptmpnode->key==k)
            break;
        else if(ptmpnode->key<k)
            ptmpnode=ptmpnode->right;
        else
            ptmpnode=ptmpnode->left;
    }
    return ptmpnode;
}

template<class T>
int RedBlackTree<T>::delete_key(const T& key)
{
    RedBlackTreeNode<T>* pnode=search_tree_node(key);
    RedBlackTreeNode<T>* replacedNode=pnode;
    RedBlackTreeNode<T>* fixupNode;
    int replacedNodeColor=pnode->color;
    if(pnode!=NIL)
    {
        if(pnode->left==NIL)
        {
            fixupNode=pnode->right;
            rb_transplant(pnode,pnode->right);
        }
        else if(pnode->right==NIL)
        {
            fixupNode=pnode->left;
            rb_transplant(pnode,pnode->left);
        }
        else
        {
            RedBlackTreeNode<T>* toReplaceNode=get_minimum(pnode->right);
            replacedNodeColor=toReplaceNode->color;
            fixupNode=toReplaceNode->right;
            if(get_parent(toReplaceNode)==pnode)
            {
                fixupNode->parent=toReplaceNode;
            }
            else
            {
                rb_transplant(toReplaceNode,toReplaceNode->right);
                toReplaceNode->right=pnode->right;
                toReplaceNode->right->parent=toReplaceNode;
            };
            rb_transplant(pnode,toReplaceNode);
            toReplaceNode->left=pnode->left;
            toReplaceNode->left->parent=toReplaceNode;
            toReplaceNode->color=pnode->color;
        }
        if(replacedNodeColor==BLACK)
                rb_delete_fixup(fixupNode);
        return 0;
    }
    return -1;
}

template<class T>
void RedBlackTree<T>::make_empty(RedBlackTreeNode<T>* root)
{
    RedBlackTreeNode<T>* pleft=root->left;
    RedBlackTreeNode<T>* pright=root->right;
    if(root)
    {
        delete root;
        if(pleft!=NIL)
            make_empty(pleft);
        if(pright!=NIL)
            make_empty(pright);
    }
}

template<class T>
void RedBlackTree<T>::inorder_tree_walk() const
{
    if(NULL!=root)
    {
        stack<RedBlackTreeNode<T>* > tmpStack;
        RedBlackTreeNode<T>* pnode=root;
        while(pnode!=NIL||!tmpStack.empty())
        {
            if(pnode!=NIL)
            {
                tmpStack.push(pnode);
                while(pnode->left!=NIL)
                {
                    pnode=pnode->left;
                    tmpStack.push(pnode);
                }
            }
            pnode=tmpStack.top();
            tmpStack.pop();
            cout<<pnode->key<<" : ";
            if(pnode->color==RED)
                cout<<"RED"<<endl;
            else
                cout<<"BLACK"<<endl;
            pnode=pnode->right;
        }
    }
}

template<class T>
int RedBlackTree<T>::get_maximum(T& ret) const
{
    if(root!=NULL)
    {
        ret=get_maximum(root)->key;
        return 0;
    }
    return -1;
}

template<class T>
int RedBlackTree<T>::get_minimum(T& ret) const
{
    if(root!=NULL)
    {
        ret=get_minimum(root)->key;
        return 0;
    }
    return -1;
}

template<class T>
int RedBlackTree<T>::get_successor(const T& k,T& ret) const
{
    if(NULL!=root)
    {
        RedBlackTreeNode<T>* pnode=search_tree_node(k);
        if(pnode!=NIL)
        {
            ret=get_successor(pnode)->key;
            return 0;
        }
        return -1;
    }
    return -1;
}

template<class T>
int RedBlackTree<T>::get_predecessor(const T& k,T& ret) const
{
    if(NULL!=root)
    {
        RedBlackTreeNode<T>* pnode=search_tree_node(k);
        if(pnode!=NIL)
        {
            ret=get_predecessor(pnode)->key;
            return 0;
        }
        return -1;
    }
    return -1;
}

template<class T>
bool RedBlackTree<T>::search_element(const T& key) const
{
    return (NIL!=search_tree_node(key));
}
int _tmain(int argc, _TCHAR* argv[])
{
    RedBlackTree<int> rbtree;
    int value;
    rbtree.insert_key(41);
    rbtree.insert_key(38);
    rbtree.insert_key(31);
    rbtree.insert_key(12);
    rbtree.insert_key(19);
    rbtree.insert_key(8);
    cout<<"root is: "<<rbtree.get_root()->key<<endl;
    cout<<"Inorder walk red black tree:"<<endl;
    rbtree.inorder_tree_walk();
    if(rbtree.get_minimum(value) == 0)
        cout<<"minmum is: "<<value<<endl;
    if(rbtree.get_maximum(value) == 0)
        cout<<"maxmum is: "<<value<<endl;
    if(rbtree.get_successor(19,value) == 0)
        cout<<"19 successor is: "<<value<<endl;
    if(rbtree.get_predecessor(19,value) == 0)
        cout<<"19 predecessor is: "<<value<<endl;
    if(rbtree.delete_key(38)==0)
        cout<<"delete 38 successfully"<<endl;
     cout<<"root is: "<<rbtree.get_root()->key<<endl;
    cout<<"Inorder walk red black tree:"<<endl;
    rbtree.inorder_tree_walk();
    return 0;
}
View Code

最終結果爲:

示例參考自:http://www.cnblogs.com/Anker/archive/2013/01/30/2882773.html

相關文章
相關標籤/搜索