數據結構學習之紅黑樹篇(Java)

紅黑樹也首先是一顆二分搜索樹,然後還要滿足一下定義(算法導論中的定義):

  1. 每個節點或者是紅色的,或者是黑色的
  2. 根節點是黑色的
  3. 每一個葉子節點(最後的空節點)是黑色的
  4. 如果一個節點是紅色的,那麼他的孩子節點都是黑色的
  5. 從任意一個節點到葉子節點,經過的黑色節點是一樣的

利用紅黑樹與2-3樹的等價性,有利於理解紅黑樹的實現。
使用java實現簡單的左傾紅黑樹的增加功能(不滿足紅黑樹任何不平衡都會在三次旋轉內解決):

/**
 * @author ymn
 * @version 1.0
 * @date 2020\6\3 0003 14:17
 */
public class RBTree<K extends Comparable<K>,V> {

    private static final boolean RED = true;
    private static final boolean BLACK = false;

    private class Node{
        public K key;
        public V value;
        public Node left,right;
        public boolean color;

        public Node(K key,V value){
            this.key = key;
            this.value = value;
            left = null;
            right = null;
            color = RED;
        }
    }

    private Node root;
    private int size;

    public int getSize(){
        return size;
    }

    public boolean isEmpty(){
        return size == 0;
    }

    public boolean isRed(Node node){
        if (node == null)
            return BLACK;
        return node.color;
    }

    //     node                     x
    //     /  \      左旋轉        /   \
    //    T1   x     ------>   node    T3
    //        / \              /  \
    //       T2 T3            T1  T2
    private Node leftRotate(Node node){
        Node x = node.right;
        node.right = x.left;
        x.left = node;
        x.color = node.color;
        node.color = RED;
        return x;
    }

    //顏色翻轉(對應2-3樹中分裂與向上兼容的過程)
    private void flipColors(Node node){
        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
    }

    //     node                     x
    //     /  \      右旋轉        /   \
    //    x   T2     ------>     y    node
    //   / \                          /  \
    //  y  T1                        T1  T2
    private Node rightRotate(Node node){
         Node x = node.left;
         node.left = x.right;
         x.right = node;
         x.color = node.color;
         node.color = RED;
         return x;
    }

    //向紅黑樹中添加新的元素(key,value)
    public void add(K key,V value){
        root = add(root,key,value);
        //保持根節點爲黑色
        root.color = BLACK;
    }

    //向以node爲根的紅黑樹樹中插入元素(key,value),遞歸算法
    //返回插入新節點後紅黑樹樹的根
    private Node add(Node node,K key,V value){
        if(node == null){
            size ++;
            return new Node(key, value);//默認插入紅色節點
        }
        if (key.compareTo(node.key) < 0){
            node.left = add(node.left,key, value);
        }else if(key.compareTo(node.key) > 0){ //插入重複元素說明什麼也不做
            node.right = add(node.right,key, value);
        }else {
            node.value = value;
        }
        //節點插入完後進行紅黑樹性質的維護
        /*先判斷一下當前節點需不需要左旋轉,即當前節點的右孩子是紅節點而左孩子不是紅節點,因爲如果左孩子是紅節點的話,
        我們需要做的是顏色翻轉,而不是左旋轉*/
        if (isRed(node.right) && !isRed(node.left))
            node = leftRotate(node);
        //當前節點的左孩子與左孩子的左孩子都爲紅節點,進行一次右旋轉
        if (isRed(node.left) && isRed(node.left.left))
            node = rightRotate(node);
        //最後判斷一下當前節點需不需要進行顏色翻轉
        if (isRed(node.left) && isRed(node.right))
            flipColors(node);
        return node;
    }

    //返回以node爲根節點的紅黑樹中,key所在的節點
    private Node getNode(Node node,K key){
        if (node == null){
            return null;
        }
        if (key.compareTo(node.key) == 0){
            return node;
        }else if (key.compareTo(node.key) < 0){
            return getNode(node.left,key);
        }else {   //key.compareTo(node.key) > 0
            return getNode(node.right,key);
        }
    }

    public boolean contains(K key){
        return getNode(root,key) != null;
    }

    public V get(K key){
        Node node = getNode(root,key);
        return node == null ? null : node.value;
    }

    public void set(K key, V value) {
        Node node = getNode(root,key);
        if (node == null){
            throw new IllegalArgumentException(key + "dose't exist!");
        }
        node.value = value;
    }
}

java中,TreeMap和TreeSet底層都是用紅黑樹實現的。

紅黑樹的性能總結:
對於完全隨機的數據,普通的二分搜索樹就很好用;
普通的二分搜索樹的缺點:極端情況下退化成鏈表(或高度不平衡樹);
當你的應用場景查詢操作很多的時候,AVL樹很好用 ;
紅黑樹犧牲了平衡性(2logn的高度)
紅黑樹的統計性能更優(平均來看,綜合增刪改查所有的操作更優)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章