小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

紅黑樹(Red Black Tree)

 webgj 2009-03-24

今天我們來介紹另一種平衡二叉樹:紅黑樹(Red Black Tree),紅黑樹由Rudolf Bayer1972年發(fā)明,當時被稱為平衡二叉B樹(symmetric binary B-trees),1978年被Leonidas J. Guibas Robert Sedgewick改成一個比較摩登的名字:紅黑樹。

紅黑樹和之前所講的AVL樹類似,都是在進行插入和刪除操作時通過特定操作保持二叉查找樹的平衡,從而獲得較高的查找性能。自從紅黑樹出來后,AVL樹就被放到了博物館里,據(jù)說是紅黑樹有更好的效率,更高的統(tǒng)計性能。不過在我了解了紅黑樹的實現(xiàn)原理后,并不相信這是真的,關(guān)于這一點我們會在后面進行討論。

紅黑樹和AVL樹的區(qū)別在于它使用顏色來標識結(jié)點的高度,它所追求的是局部平衡而不是AVL樹中的非常嚴格的平衡。之前我們在講解AVL樹時,已經(jīng)領(lǐng)教過AVL樹的復(fù)雜,但AVL樹的復(fù)雜比起紅黑樹來說簡直是小巫見大巫。紅黑樹是真正的變態(tài)級數(shù)據(jù)結(jié)構(gòu)。

首先來一個Silverlight做的紅黑樹的動畫,它有助于幫你理解什么是紅黑樹。這里需要注意,必須安裝Silverlight 2.0 RTW 才能正常運行游戲,下載地址:

http://www.microsoft.com/silverlight/resources/install.aspx?v=2.0

使用注意事項:

l         結(jié)點只接收整數(shù),如果在添加和刪除操作中輸入非法字串,則會隨機添加或刪除一個0~99之間的整數(shù)。

l         可以不在編輯框中輸入數(shù)字,直接單擊添加和刪除按鈕進行添加和刪除操作。

l         可以拖動拖動條控制動畫速度。

紅黑樹的平衡

紅黑樹首先是一棵二叉查找樹,它每個結(jié)點都被標上了顏色(紅色或黑色),紅黑樹滿足以下5個性質(zhì):

1、 每個結(jié)點的顏色只能是紅色或黑色。

2、 根結(jié)點是黑色的。

3、 每個葉子結(jié)點都帶有兩個空的黑色結(jié)點(被稱為黑哨兵),如果一個結(jié)點n的只有一個左孩子,那么n的右孩子是一個黑哨兵;如果結(jié)點n只有一個右孩子,那么n的左孩子是一個黑哨兵。

4、 如果一個結(jié)點是紅的,則它的兩個兒子都是黑的。也就是說在一條路徑上不能出現(xiàn)相鄰的兩個紅色結(jié)點。

5、 對于每個結(jié)點來說,從該結(jié)點到其子孫葉結(jié)點的所有路徑上包含相同數(shù)目的黑結(jié)點。

紅黑樹的這5個性質(zhì)中,第3點是比較難理解的,但它卻非常有必要。我們看圖1中的左邊這張圖,如果不使用黑哨兵,它完全滿足紅黑樹性質(zhì),結(jié)點50到兩個葉結(jié)點8和葉結(jié)點82路徑上的黑色結(jié)點數(shù)都為2個。但如果加入黑哨兵后(如圖1右圖中的小黑圓點),葉結(jié)點的個數(shù)變?yōu)?/span>8個黑哨兵,根結(jié)點50到這8個葉結(jié)點路徑上的黑高度就不一樣了,所以它并不是一棵紅黑樹。

 

 

要看真正的紅黑樹請在以上動畫中添加幾個結(jié)點,看看是否滿足以上性質(zhì)。

紅黑樹的旋轉(zhuǎn)操作

紅黑樹的旋轉(zhuǎn)操作和AVL樹一樣,分為LL、RR、LR、RL四種旋轉(zhuǎn)類型,差別在于旋轉(zhuǎn)完成后改變的是結(jié)點的顏色,而不是平衡因子。旋轉(zhuǎn)動畫演示請參考AVL這篇文章中的Flash動畫:

http://www.cnblogs.com/abatei/archive/2008/11/17/1335031.html

紅黑樹上結(jié)點的插入

在討論紅黑樹的插入操作之前必須要明白,任何一個即將插入的新結(jié)點的初始顏色都為紅色。這一點很容易理解,因為插入黑點會增加某條路徑上黑結(jié)點的數(shù)目,從而導(dǎo)致整棵樹黑高度的不平衡。但如果新結(jié)點父結(jié)點為紅色時(如圖2所示),將會違返紅黑樹性質(zhì):一條路徑上不能出現(xiàn)相鄰的兩個紅色結(jié)點。這時就需要通過一系列操作來使紅黑樹保持平衡。

 

 

 

為了清楚地表示插入操作以下在結(jié)點中使用“新”字表示一個新插入的結(jié)點;使用“父”字表示新插入點的父結(jié)點;使用“叔”字表示“父”結(jié)點的兄弟結(jié)點;使用“祖”字表示“父”結(jié)點的父結(jié)點。插入操作分為以下幾種情況:

1、黑父

如圖3所示,如果新點的父結(jié)點為黑色結(jié)點,那么插入一個紅點將不會影響紅黑樹的平衡,此時插入操作完成。紅黑樹比AVL樹優(yōu)秀的地方之一在于黑父的情況比較常見,從而使紅黑樹需要旋轉(zhuǎn)的幾率相對AVL樹來說會少一些。

 

 

 

2.紅父

如果新點的父結(jié)點為紅色,這時就需要進行一系列操作以保證整棵樹紅黑性質(zhì)。如圖3所示,由于父結(jié)點為紅色,此時可以判定,祖父結(jié)點必定為黑色。這時需要根據(jù)叔父結(jié)點的顏色來決定做什么樣的操作。青色結(jié)點表示顏色未知。由于有可能需要根結(jié)點到新點的路徑上進行多次旋轉(zhuǎn)操作,而每次進行不平衡判斷的起始點(我們可將其視為新點)都不一樣。所以我們在此使用一個藍色箭頭指向這個起始點,并稱之為判定點。

 

 

 

2.1 紅叔

當叔父結(jié)點為紅色時,如圖4所示,無需進行旋轉(zhuǎn)操作,只要將父和叔結(jié)點變?yōu)楹谏?,將祖父結(jié)點變?yōu)榧t色即可。但由于祖父結(jié)點的父結(jié)點有可能為紅色,從而違反紅黑樹性質(zhì)。此時必須將祖父結(jié)點作為新的判定點繼續(xù)向上進行平衡操作。

 

 

需要注意,無論“父”在“叔”的左邊還是右邊,無論“新”是“父”的左孩子還是右孩子,它們的操作都完全一樣。

 

2.2 黑叔

當叔父結(jié)點為黑色時,需要進行旋轉(zhuǎn),以下圖示了所有的旋轉(zhuǎn)可能

情形1

 

 

情形2

 

情形3

 

 

情形4

 

 

可以觀察到,當旋轉(zhuǎn)完成后,新的旋轉(zhuǎn)根全部為黑色,此時不需要再向上回溯進行平衡操作,插入操作完成。需要注意,上面四張圖的“叔”、“1”、“2”、“3”結(jié)點有可能為黑哨兵結(jié)點。

其實紅黑樹的插入操作不是很難,甚至比AVL樹的插入操作還更簡單些。但刪除操作就遠遠比AVL樹復(fù)雜得多,下面就介紹紅黑樹的刪除操作。

紅黑樹上結(jié)點的刪除

紅黑樹本身是一棵二叉查找樹,它的刪除和二叉查找樹的刪除類似。首先要找到真正的刪除點,當被刪除結(jié)點n存在左右孩子時,真正的刪除點應(yīng)該是n的中序遍在前驅(qū),關(guān)于這一點請復(fù)習(xí)二叉查找樹的刪除。如圖9所示,當刪除結(jié)點20時,實際被刪除的結(jié)點應(yīng)該為18,結(jié)點20的數(shù)據(jù)變?yōu)?/span>18。

 

 

 

所以可以推斷出,在進行刪除操作時,真正的刪除點必定是只有一個孩子或沒有孩子的結(jié)點。而根據(jù)紅黑樹的性質(zhì)可以得出以下兩個結(jié)論:

1、 刪除操作中真正被刪除的必定是只有一個紅色孩子或沒有孩子的結(jié)點

2、 如果真正的刪除點是一個紅色結(jié)點,那么它必定是一個葉子結(jié)點。

理解這兩點非常重要,如圖10所示,除了情況(a)外,其他任一種況結(jié)點N都無法滿足紅黑樹性質(zhì)。

 

 

 

在以下討論中,我們使用藍色箭頭表示真正的刪除點,它也是旋轉(zhuǎn)操作過程中的第一個判定點;真正的刪除點使用“舊”標注,舊點所在位置將被它的的孩子結(jié)點所取代(最多只有一個孩子),我們使用“新”表示舊點的孩子結(jié)點。刪除操作可分為以下幾種情形:

1、舊點為紅色結(jié)點

若舊點為紅色結(jié)點,則它必定是葉子結(jié)點,直接刪除即可。如圖11所示

 

 

 

2、一紅一黑

當舊點為黑色結(jié)點,新點為紅色結(jié)點時,將新點取代舊點位置后,將新點染成紅色即可(如圖12所示)。這里需要注意:舊點為紅色,新點為黑色的情況不可能存在。

 

 

 

3、雙黑

當舊點和新點都為黑色時(新點為空結(jié)點時,亦屬于這種情況),情況比較復(fù)雜,需要根據(jù)舊點兄弟結(jié)點的顏色來決定進行什么樣的操作。我們使用“兄”來表示舊點的兄弟結(jié)點。這里可分為紅兄和黑兄兩種情況:

3.1 紅兄

由于兄弟結(jié)點為紅色,所以父結(jié)點必定為黑色,而舊點被刪除后,新點取代了它的位置。下圖演示了兩種可能的情況:

 

 

 

紅兄的情況需要進行RRLL型旋轉(zhuǎn),然后將父結(jié)點染成紅色,兄結(jié)點染成黑色。然后重新以新點為判定點進行平衡操作。我們可以觀察到,旋轉(zhuǎn)操作完成后,判定點沒有向上回溯,而是降低了一層,此時變成了黑兄的情況。

3.2 黑兄

黑兄的情況最為復(fù)雜,需要根據(jù)黑兄孩子結(jié)點(這里用“侄”表示)和父親結(jié)點的顏色來決定做什么樣的操作。

3.2.1 黑兄二黑侄紅父

如圖14所示,這種情況比較簡單,只需將父結(jié)點變?yōu)楹谏?,兄結(jié)點變?yōu)楹谏陆Y(jié)點變?yōu)楹谏纯?,刪除操作到此結(jié)束。

 

 

 

3.2.2 黑兄二黑侄黑父

如圖15所示,此時將父結(jié)點染成新結(jié)點的顏色,新結(jié)點染成黑色,兄結(jié)點染成黑色即可。當新結(jié)點為紅色時,父結(jié)點被染成紅色,此時需要以父結(jié)點為判定點繼續(xù)向上進行平衡操作。

 

 

 

3.2.3 黑兄紅侄

黑兄紅侄有以下四種情形,下面分別進行圖示:

情形1

 

 

情形2

 

情形3

 

情形4

 

 

 

由以上圖例所示,看完以上四張圖的兄弟有可能會有一個疑問,如果情形1和情形2中的兩個侄子結(jié)點都為紅色時,是該進行LL旋轉(zhuǎn)還是進行LR旋轉(zhuǎn)呢?答案是進行LL旋轉(zhuǎn)。情形3和情形4則是優(yōu)先進行RR旋轉(zhuǎn)的判定。

紅黑樹的代碼實現(xiàn)

本以為紅黑樹的代碼非常容易,因為System.Collections.Generic.SortedDictionary類就是使用紅黑樹實現(xiàn)的,把代碼的算法部分摳出來就搞定了。但看了SortedDictionary源碼后有些失望,C#中真正實現(xiàn)紅黑樹的是TreeSet類,SortedDictionary只是在TreeSet的基礎(chǔ)上進一步抽象,加上了Key/Value泛型對。TreeSet使用了一種新的紅黑樹算法,它在搜索插入點和刪除點時預(yù)先進行旋轉(zhuǎn)和染色操作,從而避免插入和刪除后的回溯。這種算法看上去很美,但仔細想想,如果插入的是一個已經(jīng)存在的結(jié)點,刪除的結(jié)點并不存在,那這些預(yù)平衡處理不是白做了嗎?更可怕的是如果在一條路徑上間隔進行一次插入和一次刪除,而這些操作沒有命中目標,那么大家就會看到結(jié)點的顏色變來變?nèi)ィ@些都是無用功。來看看在尋找插入和刪除點的路徑上TreeSet每前進一步都要做些什么:給四個變量賦值;判斷每個結(jié)點的兩個孩子結(jié)點的顏色。這種算法在《java數(shù)據(jù)結(jié)構(gòu)和算法》這本書中有詳細講述,不過只講解了插入算法。另外國內(nèi)也專門有一篇論文描述這個算法,他的測試結(jié)果是這種算法優(yōu)于其他算法,估計測試時沒有不命中目標的情況發(fā)生??傊也⒉幌嘈胚@是一個好的算法。

為了證實我的想法,我不得不自己實現(xiàn)紅黑樹,實現(xiàn)思路跟AVL樹很類似,也是使用一個數(shù)組保存訪問路徑以進行回溯,當然,考慮到紅黑樹不嚴格的平衡,數(shù)組的長度設(shè)為64,這并不會給性能帶來什么影響。過程很艱辛,需要做大量測試。很不幸,寫完后繼續(xù)做紅黑樹的Silverlight動畫時不小心把原來的代碼給覆蓋掉了,結(jié)點刪除部分的代碼丟失。當時幾乎崩潰,不過重寫并沒有我想象的那么困難,很快完成,感覺思路清晰了很多,實現(xiàn)比原來也有了改進,感謝上帝!

下面把代碼貼出來,如果理解了上面所講內(nèi)容是很容易讀懂這些代碼的。

 

 

using System;
namespace PaintBST
{
    
public class RBTree : IBinaryTree //實現(xiàn)畫樹接口
    {    //成員變量
        private Node _head; //頭指針
        private Node[] path = new Node[32]; //記錄訪問路徑上的結(jié)點
        private int p; //表示當前訪問到的結(jié)點在_path上的索引
        INode IBinaryTree.Head //顯式接口實現(xiàn)
        {
            
get { return (INode)_head; }
       }
        
public bool Add(int value) //添加一個元素
         {  //如果是空樹,則新結(jié)點成為二叉排序樹的根
            if (_head == null)
            {
                _head 
= new Node(value);
                _head.IsRed 
= false;
                
return true;
            }
            p 
= 0;
            
//parent為上一次訪問的結(jié)點,current為當前訪問結(jié)點
            Node parent = null, current = _head;
            
while (current != null)
            {
                path[p
++= current; //將路徑上的結(jié)點插入數(shù)組
                
//如果插入值已存在,則插入失敗
                if (current.Data == value)
                {
                    
return false;
                }
                parent 
= current;
                
//當插入值小于當前結(jié)點,則繼續(xù)訪問左子樹,否則訪問右子樹
                current = (value < parent.Data) ? parent.Left : parent.Right;
            }
            current 
= new Node(value); //創(chuàng)建新結(jié)點
              current.IsRed = true;
            
if (value < parent.Data) //如果插入值小于雙親結(jié)點的值
              {
                parent.Left 
= current; //成為左孩子
              }
            
else //如果插入值大于雙親結(jié)點的值
              {
                parent.Right 
= current; //成為右孩子
              }
            
if (!parent.IsRed)
            {
                
return true;
            }
            path[p] 
= current;
            
//回溯并旋轉(zhuǎn)
            while ((p -= 2>= 0//現(xiàn)在p指向插入點的祖父結(jié)點
            {
                Node grandParent 
= path[p];
                parent 
= path[p + 1];
                
if (!parent.IsRed)
                {
                    
break;
                }
                Node uncle 
= grandParent.Left == parent ? grandParent.Right : grandParent.Left;
                current 
= path[p + 2];
                
if (IsRed(uncle)) //叔父存在并且為紅色的情況
                  {
                    parent.IsRed 
= false;
                    uncle.IsRed 
= false;
                    
if (p > 0//如果祖父不是根結(jié)點,則將其染成紅色
                       {
                        grandParent.IsRed 
= true;
                    }
                }
                
else //叔父不存在或為黑的情況需要旋轉(zhuǎn)
                  {
                    Node newRoot;
                    
if (grandParent.Left == parent) //如果當前結(jié)點及父結(jié)點同為左孩子或右孩子
                       {
                        newRoot 
= (parent.Left == current) ? LL(grandParent) : LR(grandParent);
                    }
                    
else
                    {
                        newRoot 
= (parent.Right == current) ? RR(grandParent) : RL(grandParent);
                    }
                    grandParent.IsRed 
= true//祖父染成紅色
                    newRoot.IsRed = false//新根染成黑色
                    
//將新根同曾祖父連接
                    ReplaceChildOfNodeOrRoot((p > 0? path[p - 1] : null, grandParent, newRoot);
                    
return true//旋轉(zhuǎn)后不需要繼續(xù)回溯,添加成功,直接退出
                  }
            }
            
return true;
        }
        
//旋轉(zhuǎn)根旋轉(zhuǎn)后換新根
        private void ReplaceChildOfNodeOrRoot(Node parent, Node child, Node newChild)
        {
            
if (parent != null)
            {
                
if (parent.Left == child)
                {
                    parent.Left 
= newChild;
                }
                
else
                {
                    parent.Right 
= newChild;
                }
            }
            
else
            {
                _head 
= newChild;
            }
        }
        
private static bool IsBlack(Node node)
        {
            
return ((node != null&& !node.IsRed);
        }

        
private static bool IsNullOrBlack(Node node)
        {
            
if (node != null)
            {
                
return !node.IsRed;
            }
            
return true;
        }

        
private static bool IsRed(Node node)
        {
            
return ((node != null&& node.IsRed);
        }
        
//刪除指定值
        public bool Remove(int value)
        {
            p 
= -1;
            
//parent表示雙親結(jié)點,node表示當前結(jié)點
            Node node = _head;
            
//尋找指定值所在的結(jié)點
            while (node != null)
            {
                path[
++p] = node;
                
//如果找到,則調(diào)用RemoveNode方法刪除結(jié)點
                if (value == node.Data)
                {
                    RemoveNode(node);
//現(xiàn)在p指向被刪除結(jié)點
                    return true//返回true表示刪除成功
                }
                
if (value < node.Data)
                {   
//如果刪除值小于當前結(jié)點,則向左子樹繼續(xù)尋找
                    node = node.Left;
                }
                
else
                {   
//如果刪除值大于當前結(jié)點,則向右子樹繼續(xù)尋找
                    node = node.Right;
                }
            }
            
return false//返回false表示刪除失敗
        }
        
//刪除指定結(jié)點
        private void RemoveNode(Node node)
        {
            Node tmp 
= null//tmp最終指向?qū)嶋H被刪除的結(jié)點
            
//當被刪除結(jié)點存在左右子樹時
            if (node.Left != null && node.Right != null)
            {
                tmp 
= node.Left; //獲取左子樹
                path[++p] = tmp;
                
while (tmp.Right != null//獲取node的中序遍歷前驅(qū)結(jié)點,并存放于tmp中
                {   //找到左子樹中的最右下結(jié)點
                    tmp = tmp.Right;
                    path[
++p] = tmp;
              }
                
//用中序遍歷前驅(qū)結(jié)點的值代替被刪除結(jié)點的值
                node.Data = tmp.Data;
            }
            
else
            {
                tmp 
= node;
            }
            
//當只有左子樹或右子樹或為葉子結(jié)點時
            
//首先找到惟一的孩子結(jié)點
            Node newTmp = tmp.Left;
            
if (newTmp == null//如果只有右孩子或沒孩子
              {
                newTmp 
= tmp.Right;
            }
            
if (p > 0)
            {
                Node parent 
= path[p - 1];
                
if (parent.Left == tmp)
                {   
//如果被刪結(jié)點是左孩子
                    parent.Left = newTmp;
                }
                
else
                {   
//如果被刪結(jié)點是右孩子
                    parent.Right = newTmp;
                }
                
if (!tmp.IsRed && IsRed(newTmp))
                {
                    newTmp.IsRed 
= false;
                    
return;
                }
            }
            
else  //當刪除的是根結(jié)點時
              {
                _head 
= newTmp;
                
if (_head != null)
                {
                    _head.IsRed 
= false;
                }
                
return;
            }
            path[p] 
= newTmp;

            
//如果被刪除的是紅色結(jié)點,則它必定是葉子結(jié)點,刪除成功,返回
            if (IsRed(tmp))
            {
                
return;
            }
            
//刪除完后進行旋轉(zhuǎn),現(xiàn)在p指向?qū)嶋H被刪除的位置,這個位置可能為空,tmp指向被刪除的舊點,
            while (p > 0)
            {   
//剩下的是雙黑的情況
                
//首先找到兄弟結(jié)點
                Node current = path[p];
                Node parent 
= path[p - 1];
                
bool currentIsLeft = (parent.Left == current);
                Node sibling 
= currentIsLeft ? parent.Right : parent.Left;
                
//紅兄的情況,需要LL旋轉(zhuǎn)或RR旋轉(zhuǎn)
                if (IsRed(sibling))
                {
                    Node newRoot;
                    
if (currentIsLeft)
                    {
                        newRoot 
= RR(parent);
                    }
                    
else
                    {
                        newRoot 
= LL(parent);
                    }
                    ReplaceChildOfNodeOrRoot(p 
> 1 ? path[p - 2] : null, parent, newRoot);
                    sibling.IsRed 
= false;
                    parent.IsRed 
= true;
                    
//回溯點降低
                    path[p - 1= newRoot;
                    path[p] 
= parent;
                    path[
++p] = current;
                }
                
else //黑兄的情況
                  {
                    
//黑兄二黑侄
                    if (IsNullOrBlack(sibling.Left) && IsNullOrBlack(sibling.Right))
                  {  
//紅父的情況
                        if (parent.IsRed)
                     {
                            parent.IsRed 
= false;
                            sibling.IsRed 
= true;
                            
if (current != null)
                            {
                                current.IsRed 
= false;
                            }
                            
break//刪除成功
                        }
                        
else //黑父的情況
                        {
                            parent.IsRed 
= IsRed(current);
                            
if (current != null)
                            {
                                current.IsRed 
= false;
                            }
                            sibling.IsRed 
= true;
                            p
--//需要繼續(xù)回溯
                        }
                  }
                  
else //黑兄紅侄
                    {
                        Node newRoot;
                        
if (currentIsLeft) //兄弟在右邊
                            {
                            
if (IsRed(sibling.Right)) //紅侄在右邊
                                {  //RR型旋轉(zhuǎn)
                                newRoot = RR(parent);
                                sibling.Right.IsRed 
= false;
                            }
                            
else
                            {  
//RL型旋轉(zhuǎn)
                                newRoot = RL(parent);
                            }
                        }
                        
else //兄弟在左邊
                           {
                            
if (IsRed(sibling.Left))
                            {  
//LL型旋轉(zhuǎn)
                                newRoot = LL(parent);
                                sibling.Left.IsRed 
= false;
                            }
                            
else
                            {  
//LR型旋轉(zhuǎn)
                                newRoot = LR(parent);
                            }
                        }
                        
if (current != null)
                        {
                            current.IsRed 
= false;
                        }
                        newRoot.IsRed 
= parent.IsRed;
                        parent.IsRed 
= false;
                        ReplaceChildOfNodeOrRoot(p 
> 1 ? path[p - 2] : null, parent, newRoot);
                        
break//不需要回溯,刪除成功
                    }
                }
            }
        }
        
//root為旋轉(zhuǎn)根,rootPrev為旋轉(zhuǎn)根雙親結(jié)點
        private Node LL(Node root) //LL型旋轉(zhuǎn),返回旋轉(zhuǎn)后的新子樹根
        {
            Node left 
= root.Left;
            root.Left 
= left.Right;
            left.Right 
= root;
            
return left;
        }
        
private Node LR(Node root) //LR型旋轉(zhuǎn),返回旋轉(zhuǎn)后的新子樹根
         {
            Node left 
= root.Left;
            Node right 
= left.Right;
            root.Left 
= right.Right;
            right.Right 
= root;
            left.Right 
= right.Left;
            right.Left 
= left;
            
return right;
        }
        
private Node RR(Node root) //RR型旋轉(zhuǎn),返回旋轉(zhuǎn)后的新子樹根
         {
            Node right 
= root.Right;
            root.Right 
= right.Left;
            right.Left 
= root;
            
return right;
        }
        
private Node RL(Node root) //RL型旋轉(zhuǎn),返回旋轉(zhuǎn)后的新子樹根
         {
            Node right 
= root.Right;
            Node left 
= right.Left;
            root.Right 
= left.Left;
            left.Left 
= root;
            right.Left 
= left.Right;
            left.Right 
= right;
            
return left;
        }
    }
}

 

 

完成紅黑樹后,做了一個比較粗糙的測試程序,對我自己實現(xiàn)的紅黑樹RBTree,C#類庫中的紅黑樹TreeSet和我自己實現(xiàn)的AVLAVLTree進行了簡單的測試,為了公平起見,我把TreeSet改成了整型版,這樣大家都站在了同一起跑線上??紤]到垃圾回收,這樣的測試并不是很精確、科學(xué),但也能說明一些問題。以后我會專門寫程序?qū)Ω鞣N常見的查找數(shù)據(jù)結(jié)構(gòu)進行測試

 

 

 

測試項目

RBTree

TreeSet

AVLTree

200000個整數(shù)順序插入(全部命中)

0.4375

0.4844

0.3437

200000個整數(shù)順序插入后順序刪除(全部命中,只對刪除部分計時)

0.25

0.5

0.20

200000個整數(shù)隨機插入(全部命中)

0.4375

0.5469

0.5

200000個整數(shù)隨機插入后順序刪除(全部命中,只對刪除部分計時)

0.5

0.7343

0.4219

200000個整數(shù)順序插入(一半命中)

0.297

0.344

0.234

100000個整數(shù)隨機插入后順序刪除(一半命中,只對刪除部分計時)

0.094

0.203

0.109

 

后記

測試結(jié)果基本證實了我的想法,惟一意外的是AVL樹有兩個項目輸給了RBTree。在理論上,RBTree在某些方面的確是比AVL樹更為優(yōu)秀,但從程序員的角度來說,紅黑樹的實現(xiàn)需要調(diào)用大量方法,比如結(jié)點顏色的判斷,這會抵消紅黑樹的性能優(yōu)勢。國外網(wǎng)站也有針對紅黑樹和AVL樹的測試,結(jié)果基本上是AVL樹勝出。

紅黑樹的動畫還有一些bug,整體效果也不盡如人意,我也懶得再改了,寫它比寫紅黑樹困難些。寫它主要是為了學(xué)習(xí)Silverlight,這也算是第一個Silverlight動畫作品,東西弄懂了就不想再動了。打算將來更深入地了解Silverlight后再全面修改這個動畫。


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多