完全理解紅黑樹

從二叉查找樹、2-3樹完全理解紅黑樹

引言

在學習紅黑樹的時候,看了不少文章,發現都沒有講明白紅黑樹的原理,只是簡單列了紅黑樹的幾條規則,就開始講解紅黑樹的插入,讓人一直不知其因此然。也很難深入的理解紅黑樹。
最後翻起了《算法》這本書,仔細瞭解了二叉樹查找樹、2-3樹、紅黑樹,才明白了紅黑樹不是無緣無故產生的,而是符合科學的發展觀念是按部就班,站在巨人的肩旁上發展起來的。html

這也是咱們從學生時代的填鴨式的學習方式的轉變,不單單是隻學習結論,而且要了解結論產生的歷史及發展。
這樣咱們才能從搬磚、碼農成長爲工程師、科學家。java

數據結構的演進

一位計算機科學的大牛說過:node

程序 = 數據結構 + 算法

數據結構是爲了減小查詢、刪除的時間複雜度和空間複雜度。git

鏈表的一個節點是由:節點值、節點的下一個節點(字節點)的地址
二叉查找樹一個節點:節點值、節點的左子節點的地址、節點的右子節點的地址
2-3樹:由2節點、3節點組成github

![圖. 2節點 3節點]()算法

2節點:
微信

3節點:
markdown

紅黑樹(平衡二叉查找樹):節點值、節點的左子節點、節點的右子節點、節點顏色數據結構

二叉查找樹

二叉查找樹:是由2節點的樹組成的,最壞的時間複雜度是O(N)

插入的幾種狀況:學習

  1. 樹爲空插入的節點做爲根節點
  2. 插入的節點等於子樹的值,則樹不增長節點
  3. 插入的節點大於最終查詢的子樹則做爲子樹的右節點
  4. 插入的節點小於最終查詢的子樹則做爲子樹的左節點

根據以上的四種狀況,咱們能夠看出,若是咱們插入的值是從1開始逐漸遞增的,那麼樹就最終生長得很像鏈表。

節點的實現

2節點

private Node<T> root = null;//根節點

private class Node<T>{

    public T value;//爲了下面的簡單演示設屬性爲 pubilc
    public Node<T> left;//真正使用的時候應該爲private 用get、set方法訪問
    public Node<T> right;
    public Node<T> parent;

    public Node(T value, Node<T> parent) {
        this.value = value;
        this.parent = parent;
    }
}

查找

若是查找的值等於根節點的值,那麼查找命中,不然遞歸的在根的子樹中(經過比較與根節點的值選擇左/右節點)查找。

//返回null 樹中沒有此節點 ,遞歸的下左/右子節點查詢
    public Node<T> get(T value){

        Node<T> node = root;

        while(true){
            if(node == null){
                return null;
            }
            if(node.value == value){
                return node;
            }else if(node.value > value){
                if(node.right == null){
                    return null;
                }else if(node.right.value == value){
                    return node.right;
                }
                node = node.right;
            }else if(node.value < value){
                if(node.left == null){
                    return null;
                }else if(node.left.value == value){
                    return node.left;
                }
                node = node.left;
            }
        }
    }

插入

插入和查找很像,若是樹的根節點爲空(空樹)則插入到根節點,不然遞歸的在子樹中判斷,當子樹爲null的時候,插入。

public Node<T> put(T value){

    Node<T> node = root;

    while(true){
        if(node == null){
            Node<T> node1 = new Node<>(value,null);
            root = node1;//空樹,插入的爲根節點
            return node1;
        }
        if(node.value == value){
            return node;
        }else if(node.value > value){
            if(node.right == null){
                Node<T> node1 = new Node<>(value,node);
                node.right = node1;
                return  node1;
            }else if(node.right.value == value){
                return node.right;
            }
            node = node.right;
        }else if(node.value < value){
            if(node.left == null){
                Node<T> node1 = new Node<>(value,node);
                node.left  = node1;
                return node1;
            }else if(node.left.value == value){
                return node.left;
            }
            node = node.left;
        }
    }
}

2-3樹

爲了解決二叉查找樹的不平衡,2-3樹孕育而生,2-3樹可以很好的實現樹的平衡。
2-3樹的節點再也不是單一的2節點,節點多是2節點、3節點。

2節點:有一個值,兩個子節點
3節點:有兩個值,三個子節點。

注意二叉查找樹是向下生長,而2-3樹是向上生長。
當2-3的根節點由3樹生長爲(紅黑樹中的旋轉)2節點,樹的高度增長。

查找

2-3樹的查找和二叉查找樹的思路是相同的都是迭代的思想。不過不一樣的是在判斷節點是否相同時2-3樹要判斷是否相等於左值或右值,若是大於左值小於右值,則從中子節點開始遞歸。

插入

2-3樹的插入有如下幾種狀況:

樹爲空

插入的節點做爲根節點而且爲2節點。
圖

2節點中插入

插入的節點爲2節點,2節點轉化爲3節點。

2節點生長爲3節點

3節點中插入

插入的節點爲3節點,則臨時調整3節點爲4節點(三個值),4節點中的中值變爲左右值的父。

父節點爲null

則4節點,轉化爲3個2節點。
3節點中插入

父爲2節點

則4節點的中子轉化爲父節點的值,父節點轉化爲3節點。
3節點插入父爲2節點

父爲3節點

則3節點的中子節點轉爲父節點的值,父節點臨時轉化爲4節點,此時就變成了插入的節點爲3節點的狀況上面的兩種狀況。

父爲3節點1

父爲3節點2

對比二叉樹和2-3樹,從1遞增插入10,對比樹的形狀

二叉查找樹

經過對比,2-3和二叉樹的上圖的插入,能夠看到2-3最終是會自平衡的,而二叉查找樹最壞會變成鏈表的形式(長的像鏈表).

紅黑樹

紅黑樹實際上是2-3樹的一種只含2節點的表現形式。仍是二叉樹節點大於左子節點,小於右子節點。

咱們把2-3樹中的2節點用黑色表示,3節點用紅色表示(3節點的左節點爲黑色、右節點爲紅色)

將紅色連接畫平就是2-3樹。

2-3樹紅黑樹變化圖

紅黑樹的性質

  1. 每一個節點要麼是紅色,要麼是黑色(2-3樹節點要麼是2節點要麼是3節點)
  2. 根節點必須是黑色
  3. 紅色節點不能連續(紅色節點的子和父不能爲紅)(不能有4節點。注意2-3的4節點是臨時的)
  4. 對於每一個節點,從該點至null(樹的尾端)的任何路徑,都含有相同個數的黑色節點。

左旋 右旋

左旋、右旋其實就是2-3樹的3節點臨時變爲4節點,4節點的分解。

左旋

左旋

右旋

右旋

插入

把紅黑樹的插入當作是2-3樹的插入,就能明白紅黑樹的節點插入,節點的旋轉,及根據紅黑樹的

2-3樹紅黑樹變化圖

對比2-3的幾種插入狀況,就能理解紅黑樹的插入狀況。

參考

https://github.com/CarpenterL...

一個紅黑樹生成過程: https://www.cs.usfca.edu/~gal...

張無忌的回答:
https://www.zhihu.com/questio...

建議看一下《算法》第四版紅皮書。
其實理解紅黑樹起來也不是那麼困難。

<br/><br/>
關注個人公衆號第一時間閱讀有趣的技術故事
掃碼關注:
也能夠在微信搜索公衆號便可關注我:codexiulian 渴望與你一塊兒成長進步!

相關文章
相關標籤/搜索