红黑树的原理_红黑树插入算法实现原理分析
-
引言
紅黑樹是在實際工程中被廣泛應用的一種數據結構,比如Linux中的線程調度就是使用的紅黑樹來管理進程控制塊,而Nginx中也是使用紅黑樹來管理的timer,Java中的TreeMap和TreeSet也是基于紅黑樹來實現的。紅黑樹相比普通二叉查找樹的一個優勢就是它的樹高為~lgN,所以不管是查找/插入/刪除操作它均能保證能夠在對數時間之內完成。本文我們就先來了解一下紅黑樹插入算法的實現。
紅黑樹的定義
紅黑樹可以定義成含有紅黑鏈接并且滿足下列條件的二叉查找樹:
比如下圖就是一棵典型的紅黑樹,如果之前了解過2-3樹的話(不了解也沒有關系,我們下面的內容并不會涉及到2-3樹),可以發現如果將紅黑樹中的紅色結點畫平,實際上它就是2-3樹的一種變形,不過相比2-3樹,紅黑樹的查找操作要簡單的多,但它同時也結合了2-3樹中高效的插入操作,所以說紅黑樹其實是普通的二叉查找樹和2-3樹兩種數據結構優點的結合。
紅黑樹的定義 在實現紅黑樹之前我們先來定義一棵紅黑樹: public class RedBlackLiteBST<Key extends Comparable<Key>, Value> {private static final boolean RED = true;private static final boolean BLACK = false;private Node root; // root of the BSTprivate int n; // number of key-value pairs in BST// BST helper node data typeprivate class Node {private Key key; // keyprivate Value val; // associated dataprivate Node left, right; // links to left and right subtreesprivate boolean color; // color of parent linkpublic Node(Key key, Value val, boolean color) {this.key = key;this.val = val;this.color = color;}} }在上面的代碼中,我們將鏈接的顏色保存在表示該結點的Node對象中的color變量中。如果指向它的鏈接是紅色的,那么該變量為true,黑色則為false,我們規定空鏈接都為黑色。如下圖所示,指向結點C的鏈接是紅色,那么我們就將h.left.color設置為紅色,指向結點J的鏈接是黑色的,我們就將h.right.color設置為黑色。
紅黑樹的顏色表示
紅黑樹的幾種基本操作
紅黑樹相比普通的二叉查找樹的一個重要優勢就是插入的高效性,但是正因為如此紅黑樹的插入操作的算法實現相比普通的二叉樹要復雜一些。在正式實現插入算法之前,我們有必要先了解一下對于紅黑樹的幾種基本操作。
左旋轉
如下圖所示,現在我們有一條紅色的右鏈接,現在我們想要將這條紅色右鏈接轉換為左鏈接,這個操作過程就叫做左旋轉:
左旋轉之前
我們要做的就是在保持紅黑樹平衡性的同時,將上圖的結構變為下面這樣:
左旋轉之后
仔細觀察可以發現,我們要實現的其實就是將紅色鏈接關聯的兩個節點中由較小的節點E作為根節點轉換成由較大的節點S作為根節點。同時在這個過程中為了保持二叉樹中左子樹都要小于根節點,右子樹都要大于根節點,所以如果S節點還存在的話左鏈接我們還需要將它變成E節點的右鏈接。具體的實現代碼如下:private Node rotateLeft(Node h) {assert (h != null) && isRed(h.right);Node x = h.right;h.right = x.left;x.left = h;x.color = h.color;h.color = RED;return x;}右旋轉
右旋轉的實現和左旋轉的實現是類似的,就是將一個紅色左鏈接轉換成一個紅色右鏈接:
右旋轉之前
與左旋轉的時候相反,我們要做的其實就是紅色鏈接關聯的兩個節點中較大的節點S作為根節點轉換成由較小的節點E作為根節點:
右旋轉之后
所以轉換成具體的代碼,我們只需要將left和right相互轉換就行了:private Node rotateRight(Node h) {assert (h != null) && isRed(h.left);Node x = h.left;h.left = x.right;x.right = h;x.color = h.color;h.color = RED;return x;}顏色轉換
上面我們提到紅黑樹的一個重要特性就是紅鏈接均為做左鏈接,所以對于下面這種情形,如果一個結點的兩個子結點均為紅色鏈接,我們就將子結點的顏色全部由紅色轉換成黑色,同時將父結點的顏色由黑變紅。
顏色轉換之前
顏色轉換之后
具體的實現代碼非常簡單:private void flipColors(Node h) {assert !isRed(h) && isRed(h.left) && isRed(h.right);h.color = RED;h.left.color = BLACK;h.right.color = BLACK;}插入操作的實現
上面說了這么多,其實都是為接下來的插入操作做的預熱。接下來結合下圖,我們來分析紅黑樹插入操作過程我們會遇到的三種情形:
插入操作的3種情形
插入操作的具體實現代碼如下,下面的代碼直到// fix-up any right-leaning right之前我們做的都是為了找到合適的插入位置,而之后的3個if語句實際上就是對上圖中情形3的一種總結。public void put(Key key, Value val) {root = insert(root, key, val);root.color = BLACK;// assert check(); // Check integrity of red-black tree data structure.}private Node insert(Node h, Key key, Value val) {if (h == null) {n++;return new Node(key, val, RED);}int cmp = key.compareTo(h.key);if (cmp < 0) h.left = insert(h.left, key, val);else if (cmp > 0) h.right = insert(h.right, key, val);else h.val = val;// fix-up any right-leaning linksif (isRed(h.right) && !isRed(h.left)) h = rotateLeft(h);if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);if (isRed(h.left) && isRed(h.right)) flipColors(h);return h;}isRed的實現非常簡單,我就不解釋了:// is node x red (and non-null) ?private boolean isRed(Node x) {if (x == null) return false;return x.color == RED;}
總結
以上是生活随笔為你收集整理的红黑树的原理_红黑树插入算法实现原理分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 转换时间格式24小时_国内(上海)原油期
- 下一篇: easyui-window窗口不遮挡_眼