青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 224  文章 - 41  trackbacks - 0
<2008年11月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

享受編程

常用鏈接

留言簿(11)

隨筆分類(159)

隨筆檔案(224)

文章分類(2)

文章檔案(4)

經典c++博客

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

原文地址:http://imlazy.ycool.com/post.1104022.html

(閱讀本文之前請先了解二叉搜索樹)

紅黑樹(Red-Black Tree

紅黑樹(Red-Black Tree)是二叉搜索樹(Binary Search Tree)的一種改進。我們知道二叉搜索樹在最壞的情況下可能會變成一個鏈表(當所有節點按從小到大的順序依次插入后)。而紅黑樹在每一次插入或刪除節點之后都會花Olog N)的時間來對樹的結構作修改,以保持樹的平衡。也就是說,紅黑樹的查找方法與二叉搜索樹完全一樣;插入和刪除節點的的方法前半部分節與二叉搜索樹完全一樣,而后半部分添加了一些修改樹的結構的操作。

紅黑樹的每個節點上的屬性除了有一個key、3個指針:parent、lchild、rchild以外,還多了一個屬性:color它只能是兩種顏色:紅或黑。而紅黑樹除了具有二叉搜索樹的所有性質之外,還具有以下4點性質:(為什么只要這些性質就能解決這個問題,其實還是一個問題)

1. 根節點是黑色的。

2. 空節點是黑色的(紅黑樹中,根節點的parent以及所有葉節點lchild、rchild都不指向NULL,而是指向一個定義好的空節點)。

3. 紅色節點的父、左子、右子節點都是黑色。

4. 在任何一棵子樹中,每一條從根節點向下走到空節點的路徑上包含的黑色節點數量都相同。
   
如下圖就是一棵紅黑樹:

有了這幾條規則,就可以保證整棵樹的平衡,也就等于保證了搜索的時間為Olog N)。

但是在插入、刪除節點后,就有可能破壞了紅黑樹的性質。所以我們要做一些操作來把整棵樹修補好。下面我就來介紹一下。

首先有一個預備知識,那就是節點的Left-RotateRight-Rotate操作。所謂Left-Rotate(x)就是把節點x向左下方向移動一格,然后讓x原來的右子節點代替它的位置。而Right-Rotate當然就是把Left-Rotate左、右互反一下。如下圖:

注意,Left-Rotate(x)后,x的右子樹變成了原來y的左子樹,Right-Rotate反之。思考一下,這樣一次變換后,仍然滿足二叉搜索樹的性質中序遍歷并沒有改變)。在紅黑樹的插入、刪除中,要用到很多Left-RotateRight-Rotate操作。

//把一個節點向左下方移一格,并讓他原來的右子節點代替它的位置。
   void leftRotate(RBTNode* node)

 {
        RBTNode* right = node->rchild;
        node->rchild = right->lchild;
        node->rcount = right->lcount;
        node->rchild->parent = node;
        right->parent = node->parent;
        if (right->parent == m_null) {
            m_root = right;
        }
        else if (node == node->parent->lchild) {
            node->parent->lchild = right;
        }
        else {
            node->parent->rchild = right;
        }
        right->lchild = node;
        right->lcount += node->lcount + 1;
        node->parent = right;
    }

    //把一個節點向右下方移一格,并讓他原來的左子節點代替它的位置。
    inline void rightRotate(RBTNode* node) {
        RBTNode* left = node->lchild;
        node->lchild = left->rchild;
        node->lcount = left->rcount;
        node->lchild->parent = node;
        left->parent = node->parent;
        if (left->parent == m_null) {
            m_root = left;
        }
        else if (node == node->parent->lchild) {
            node->parent->lchild = left;
        }
        else {
            node->parent->rchild = left;
        }
        left->rchild = node;
        left->rcount += node->rcount + 1;
        node->parent = left;
    }

 

一、 插入

插入首先是按部就班二叉搜索樹的插入步驟,把新節點z插入到某一個葉節點的位置上。
   
接下來把z的顏色設成紅色。為什么?還記得紅黑樹的性質嗎,從根節點向下到空節點的每一條路徑上的黑色節點數要相同。如果新插入的是黑色節點,那么它所在的路徑上就多出了一個黑色的節點了。所以新插入的節點一定要設成紅色。但是這樣可能又有一個矛盾,如果z的父節點也是紅色,怎么辦,前面說過紅色節點的子節點必須是黑色。因此我們要執行下面一個迭代的過程,稱為Insert-Fixup,來修補這棵紅黑樹。

Insert-Fixup中,每一次迭代的開始,指針z一定都指向一個紅色的節點。如果z->parent是黑色,那我們就大功告成了;如果z->parent是紅色,顯然這就違返了紅黑的樹性質,那么我們要想辦法把z或者z->parent變成黑色,但這要建立在不破壞紅黑樹的其他性質的基礎上。

這里再引入兩個指針:grandfather,指向z->parent->parent,也就是z的爺爺(顯然由于z->parent為紅色,grandfather一定是黑色);uncle,指向grandfather除了z->parent之外的另一個子節點,也就是z的父親的兄弟,所以叫uncle

(為了說話方便,我們這里都假設z->parentgrandfather的左子節點,而unclegrandfather的右子節點。如果遇到的實際情況不是這樣,那也只要把所有操作中的左、右互反就可以了。)

在每一次迭代中,我們可能遇到以下三種情況。

Case 1. uncle也是紅色。這時只要把z->parentuncle都設成黑色,并把grandfather設成紅色。這樣仍然確保了每一條路徑上的黑色節點數不變。然后把z指向grandfather,并開始新一輪的迭代。如下圖:

1:我們可以看出左邊的圖,各條路徑包含黑顏色的數目是正確的,只是顏色不對而已,我們把它分成兩邊來看,即到節點D應該包含N+1個黑色節點,其中這個1C,而NC以上的黑色節點個數。同理A也應該是N+1B也是N+1,調整以后,看看我們確實沒有改變到A、BD的所包含的黑色節點數。下面的情況也可以同樣的方法來分析。

Case 2. uncle是黑色,并且zz->parent的右子節點。這時我們只要把z指向z->parent,然后做一次Left-Rotate(z)。就可以把情況轉化成Case 3

Case 3. uncle是黑色,并且zz->parent的左子節點。到了這一步,我們就剩最后一步了。只要把z->parent設成黑色,把grandfather設成紅色,再做一次Right-Rotate(grandfather),整棵樹就修補完畢了。可以思考一下,這樣一次操作之后,確實滿足了所有紅黑樹的性質。Case 2Case 3如下圖:

  
反復進行迭代,直到某一次迭代開始時z->parent為黑色而告終,也就是當遇到Case 3后,做完它而告終。

void insertFixup(RBTNode* insertNode) {
        RBTNode* p = insertNode;
        while (p->parent->color == RED) {

//z->parentgrandfather的左子節點,下面是三種情況
            if (p->parent == p->parent->parent->lchild) {
                RBTNode* parentRight = p->parent->parent->rchild;
                if (parentRight->color == RED) {
                    p->parent->color = BLACK;
                    parentRight->color = BLACK;
                    p->parent->parent->color = RED;
                    p = p->parent->parent;
                }
                else {
                    if (p == p->parent->rchild) {
                        p = p->parent;
                        leftRotate(p);
                    }
                    p->parent->color = BLACK;
                    p->parent->parent->color = RED;
                    rightRotate(p->parent->parent);
                }
            }
            else {
                RBTNode* parentLeft = p->parent->parent->lchild;
                if (parentLeft->color == RED) {
                    p->parent->color = BLACK;
                    parentLeft->color = BLACK;
                    p->parent->parent->color = RED;
                    p = p->parent->parent;
                }
                else {
                    if (p == p->parent->lchild) {
                        p = p->parent;
                        rightRotate(p);
                    }
                    p->parent->color = BLACK;
                    p->parent->parent->color = RED;
                    leftRotate(p->parent->parent);
                }
            }
        }
        m_root->color = BLACK;
    }

二、刪除

讓我們來回顧一下二叉搜索樹的刪除節點z的過程:如果z沒有子節點,那么直接刪除即可;如果z只有一個子節點,那么讓這個子節點來代替z的位置,然后把z刪除即可;如果z有兩個子節點,那么找到z在中序遍歷中的后繼節點s(也就是從z->rchild開始向左下方一直走到底的那一個節點),把skey賦值給zkey,然后刪除s。

紅黑樹中刪除一個節點z的方法也是首先按部就班以上的過程。

按照二叉搜索樹的刪除方法刪除節點,如果刪除節點是紅色的,那并不會改變紅黑樹的性質。如果刪除的節點是黑色的,那么顯然它所在的路徑上就少一個黑色節點,那么紅黑樹的性質就被破壞了。這時我們就要執行一個稱為Delete-Fixup的過程,來修補這棵樹。下面我就來講解一下。

一個節點被刪除之后,一定有一個它的子節點代替了它的位置(即使是葉節點被刪除后,也會有一個空節點來代替它的位置。前面說過,在紅黑樹中,空節點是一個實際存在的節點。)。我們就設指針x指向這個代替位置的節點。
顯然,如果x是紅色的,那么我們只要把它設成黑色,它所在的路徑上就重新多出了一個黑色節點,那么紅黑樹的性質就滿足了。
   
然而,如果x是黑色的,那我們就要假想x上背負了2個單位的黑色。那么紅黑樹的性質也同樣不破壞,但是我們要找到某一個紅色的節點,把x超載的這1個單位的黑色丟給它,這樣才算完成。Delete-Fixup做的就是這個工作。

注:刪除了一個黑色節點以后,遍歷到節點一下的葉子節點比遍歷其他分支的葉子節點的黑色節點數就少了一個,這就要是找到一個紅色,把這個節點換成黑色來擬補這個刪除的黑色節點,使得遍歷到葉子節點經過黑色節點的數目一樣。

Delete-Fixup同樣是一個循環迭代的過程。每一次迭代開始時,如果指針x指向一個紅色節點,那么大功告成,把它設成黑色即告終。相反如果x黑色,那么我們就會面對以下4種情況

這里引入另一個指針w,指向x的兄弟。這里我們都默認xx->parent的左子節點,則wx->parent的右子節點。(如果實際遇到相反的情況,只要把所有操作中的左、右互反一下就可以了。)

Case 1. w是紅色。這時我們根據紅黑樹的性質可以肯定x->parent是黑色、w->lchild是黑色。我們把x->parentw的顏色互換,然后做一次Left-Rotate(x->parent)。做完之后x就有了一個新的兄弟:原w->lchild,前面說過它一定是黑色的。那么我們就在不破壞紅黑樹性質的前提下,把Case 1轉換成了Case2、3、4中的一個,也就是w是黑色的情況。思考一下,這樣做不會改變每條路徑上黑色節點的個數,如下圖:

注:可以看出這樣變化以后就變成了Case2了。

Case 2. w是黑色,并且w的兩個子節點都是黑色。這時我們只要把w設成紅色。然后把x移到x->parent,開始下一輪迭代(注意,那超載1單位的黑色始終是跟著指針x走的,直到x走到了一個紅色節點上才能把它卸下)。思考一下,這一次操作不會破壞紅黑樹的性質。如下圖(圖中節點B不一定是紅色,也可能是黑色):

注:這里只要把B變成紅色就大功告成了。

Case 3. w是黑色,并且w的兩個子節點左紅右黑。這時我們把ww->lchild的顏色互換,然后做Right-Rotate(w)。思考一下,這樣做之后不會破壞紅黑樹的性質。這時x的新的兄弟就是原w->lchildCase 3被轉化成了Case 4。

Case 4. w是黑色,并且w的右子節點是紅色。一但遇到Case 4,就勝利在望了。我看下面一張圖。先把wx->parent的顏色互換,再做Left-Rotate(x->parent)。這時圖中節點E(也就是原w->rchild)所在的路徑就肯定少了一個黑色,而x所在的路徑則多了一個黑色。那么我們就把x上多余的1個單位的黑色丟給E就可以了。至此,Delete-Fixup就順利完成了。

注:通過注1我們可以看出問題在Case4后已經解決了。

void delFixup(RBTNode* delNode) {

    RBTNode* p = delNode;

    while (p != m_root && p->color == BLACK) {

       if (p == p->parent->lchild) {//左邊情況,以下是四種不同的Case

           RBTNode* sibling = p->parent->rchild;

           if (sibling->color == RED) {

              sibling->color = BLACK;

              p->parent->color = RED;

              leftRotate(p->parent);

              sibling = p->parent->rchild;

           }

           if (sibling->lchild->color == BLACK

              && sibling->rchild->color == BLACK

              ) {

              sibling->color = RED;

              p = p->parent;

           }

           else {

              if (sibling->rchild->color == BLACK) {

                  sibling->lchild->color = BLACK;

                  sibling->color = RED;

                  rightRotate(sibling);

                  sibling  = sibling->parent;

              }

              sibling->color = sibling->parent->color;

              sibling->parent->color = BLACK;

              sibling->rchild->color = BLACK;

              leftRotate(sibling->parent);

              p = m_root;

           }

       }

       else {//右邊情況

           RBTNode* sibling = p->parent->lchild;

           if (sibling->color == RED) {

              sibling->color = BLACK;

              p->parent->color = RED;

              rightRotate(p->parent);

              sibling = p->parent->lchild;

           }

           if (sibling->lchild->color == BLACK

              && sibling->rchild->color == BLACK

              ) {

              sibling->color = RED;

              p = p->parent;

           }

           else {

              if (sibling->lchild->color == BLACK) {

                  sibling->rchild->color = BLACK;

                  sibling->color = RED;

                  leftRotate(sibling);

                  sibling = sibling->parent;

              }

              sibling->color = sibling->parent->color;

              sibling->parent->color = BLACK;

              sibling->lchild->color = BLACK;

              rightRotate(sibling->parent);

              p = m_root;

           }

       }

    }

    p->color = BLACK;

}

posted on 2008-11-22 14:16 漂漂 閱讀(539) 評論(0)  編輯 收藏 引用 所屬分類: 算法
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品在线观看免费| 91久久中文| 欧美激情中文字幕一区二区| 午夜精品在线看| 亚洲资源av| 欧美专区在线观看| 久久精品国产2020观看福利| 久久久久天天天天| 欧美黄色一区二区| 国产精品久久久久久五月尺| 国产精品久久久久久影视| 国产日韩综合| 91久久精品一区二区别| 一区二区三区欧美视频| 欧美一区在线直播| 欧美成人午夜免费视在线看片| 亚洲国产精品久久精品怡红院| 欧美jizz19性欧美| 日韩一级成人av| 欧美在线二区| 欧美日韩成人综合在线一区二区 | 久久美女艺术照精彩视频福利播放| 久久久久久精| 国产精品h在线观看| 国内精品写真在线观看| 亚洲精品综合久久中文字幕| 欧美国产日韩xxxxx| 欧美午夜无遮挡| 在线看欧美日韩| 亚洲免费一级电影| 久久综合网络一区二区| 亚洲伦理网站| 美日韩精品视频免费看| 国产精品成人播放| 最近中文字幕日韩精品| 久久成人18免费网站| 亚洲欧洲在线视频| 久久午夜电影网| 国产日韩欧美91| 亚洲免费在线视频| 亚洲精品一区二区三区婷婷月| 久久精品91久久久久久再现| 国产精品久久久久999| 亚洲精品中文字幕女同| 免费欧美高清视频| 欧美在线1区| 国产欧美91| 亚洲欧美在线高清| 一本久道综合久久精品| 欧美sm视频| 亚洲国产日韩欧美| 久久亚洲精品网站| 久久精品午夜| 精品av久久久久电影| 久久黄金**| 欧美一区日韩一区| 国产一区二区三区久久| 欧美综合激情网| 亚洲资源在线观看| 国产亚洲福利社区一区| 久久精品综合一区| 久久精品视频免费| 在线精品亚洲| 欧美激情亚洲| 欧美精品在线观看| 亚洲视频播放| 亚洲美女在线看| 欧美性猛交xxxx乱大交蜜桃 | 亚洲国产成人在线| 女仆av观看一区| 久久综合久久综合九色| 亚洲国产精品一区在线观看不卡 | 亚洲韩国青草视频| 亚洲国产三级| 欧美日韩一区二区三区视频| 国产精品99久久久久久白浆小说| 最新日韩中文字幕| 国产精品福利在线观看| 亚洲欧美怡红院| 欧美在线在线| 亚洲欧洲视频在线| 亚洲免费观看高清完整版在线观看熊 | 一区二区三区.www| 国产精品二区影院| 久久婷婷久久| 模特精品在线| 亚洲一区二区免费视频| 午夜精品久久久99热福利| 国产一区二区三区免费在线观看| 久久影院午夜论| 欧美日本在线一区| 久久www免费人成看片高清| 久久精品免费观看| 一本一本a久久| 欧美综合国产精品久久丁香| 在线播放中文字幕一区| 亚洲精选久久| 在线成人国产| 国产精品99久久99久久久二8| 国产欧美一区二区三区久久| 欧美成人一区二区在线| 欧美精品日韩综合在线| 午夜国产精品影院在线观看| 久久精精品视频| 一区二区三区四区五区在线| 亚洲一区综合| 99精品热视频| 欧美资源在线| 亚洲一区二区三区中文字幕| 久久精品视频在线| 这里是久久伊人| 美国成人直播| 欧美在线一级视频| 欧美激情日韩| 久久欧美中文字幕| 国产精品欧美日韩一区| 亚洲第一福利视频| 国产精品视频网站| 亚洲国产精品999| 在线观看欧美成人| 亚洲综合欧美| 欧美一区二区三区日韩| 欧美国产激情二区三区| 欧美在线免费| 欧美性理论片在线观看片免费| 亚洲电影在线看| 在线播放视频一区| 久久综合给合久久狠狠狠97色69| 欧美一区二区三区免费大片| 欧美午夜精品理论片a级按摩| 亚洲高清免费在线| 1204国产成人精品视频| 久久www免费人成看片高清| 欧美一区二区三区成人| 国产精品久久久久久五月尺| 亚洲午夜精品福利| 亚洲欧美一区二区三区在线| 国产精品xnxxcom| 亚洲午夜久久久久久久久电影院| 这里只有精品在线播放| 国产精品99一区二区| 亚洲一区二区欧美| 欧美一区二区三区日韩视频| 国产女主播一区二区| 欧美一区二区三区视频在线| 久久国产主播| 黄网动漫久久久| 麻豆久久精品| 在线观看日韩av电影| 久热国产精品视频| 亚洲电影免费观看高清完整版| 亚洲区在线播放| 欧美精品尤物在线| 亚洲午夜视频在线观看| 久久精品盗摄| 极品少妇一区二区| 欧美.日韩.国产.一区.二区| 欧美成人精品三级在线观看| 亚洲精品一区二区三区四区高清| 欧美激情视频在线播放| 亚洲午夜久久久久久尤物| 久久久久99| 亚洲国产一区二区在线| 欧美日韩一区二区三区在线看| 亚洲视频在线播放| 久久婷婷久久| 在线视频欧美日韩| 国产综合网站| 欧美剧在线观看| 亚洲欧美视频| 美国十次了思思久久精品导航| 亚洲美女福利视频网站| 国产精品免费网站| 久久亚洲风情| 亚洲视频视频在线| 欧美高清视频一区二区| 中文成人激情娱乐网| 国产一区二区三区不卡在线观看| 免费不卡视频| 亚洲欧美日韩精品综合在线观看| 久久久免费av| 亚洲在线播放电影| 亚洲国产日韩欧美在线动漫| 国产精品久久77777| 蜜桃av噜噜一区| 午夜精品视频| 一二三区精品福利视频| 欧美成人精品在线播放| 欧美一区1区三区3区公司| 日韩亚洲欧美精品| 狠狠色综合网| 国产精品久久综合| 欧美劲爆第一页| 久久久免费观看视频| 亚洲欧美日韩高清| 亚洲精品久久久一区二区三区| 久久一二三四| 性感少妇一区| 亚洲综合色网站| 一区二区三区四区在线|