【玩转数据结构 从入门到进阶12学习笔记】红黑树

2-3树

二叉查找树中树高会受到输入数据的影响,极端情况下一棵树和一个链表没什么区别,所以我们需要一种树,它的所有叶节点到根节点的距离都是相等的,这种树为平衡树,并且随着数据的加入,这种平衡性会一直保持,它就是2-3查找树,它是一棵绝对平衡的树。

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第1张图片
如上图,存放一个元素的为2节点,存放两个元素的为3节点,对于2节点,它与二叉查找树特性相同,左链接比节点值小,右链接比节点值大,而对于3节点,它有三个链接,左链接指向的左子树所有元素都小于3节点的两个键,中间链接指向的子树元素大小介于两个键中间,右链接指向的子树元素值都大于3节点的两个键。

2-3树如何维持绝对的平衡

1.向2节点插入
向2节点插入元素,先查找,找到就更新,未找到就插入新元素,但2-3树不会添加到空节点位置上,而是与最后找到位置的叶子节点进行融合,合并成一个3节点
【玩转数据结构 从入门到进阶12学习笔记】红黑树_第2张图片
2.向3节点插入元素
(1)若插入的3节点为根节点
【玩转数据结构 从入门到进阶12学习笔记】红黑树_第3张图片
(2)若插入的3节点为叶子节点,父亲节点为2节点

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第4张图片
(3)若插入的3节点为叶子节点,父亲节点为3节点
【玩转数据结构 从入门到进阶12学习笔记】红黑树_第5张图片

红黑树

从上文的2-3树中可以知道3节点为平衡关键,这里我们用红色表示3节点,表示的意思就是它和它的父亲节点融合在一起的,【玩转数据结构 从入门到进阶12学习笔记】红黑树_第6张图片
2-3树与红黑树对应表示如下图:【玩转数据结构 从入门到进阶12学习笔记】红黑树_第7张图片

红黑树的性质

在算法导论中,红黑树基本性质有以下五条:
1.节点是红色或黑色。
2.根节点是黑色。
3.所有叶子都是黑色(叶子是NIL节点)。
4.每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5.从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点(保持黑平衡)

旋转与颜色翻转

1.左旋

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第8张图片

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;
    }

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第9张图片
2.右旋
【玩转数据结构 从入门到进阶12学习笔记】红黑树_第10张图片

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;
    }

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第11张图片
3.颜色翻转
【玩转数据结构 从入门到进阶12学习笔记】红黑树_第12张图片

  private void flipColors(Node node){

        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
    }

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第13张图片

红黑树的插入

红黑树插入的元素为红色,
1.向2节点插入元素
在2-3树中向2节点插入非常简单,直接合并成一个3节点就行。但是具体实现时,因为相对于父节点可能有大有小,那么在插入的时候就可能在父节点的左边或者右边,而这里的红黑树是左倾红黑树,红色节点只能在左边,那么当在右边插入的时候,就需要进行左旋转操作将右红节点变成左红节点。
2.向3节点插入元素
这里主要分3种情况:
(1)插入元素的值比3节点的两个值都大
这种情况则为一个黑节点连着两个红节点,直接颜色翻转
(2)插入元素比3节点的两个键都小
这种情况先进行右旋转,转变后为第一种情况,再进行颜色翻转
(3)插入的元素介于两个键中间
这种情况先左旋,左旋成第二种,继续第二种情况步骤

【玩转数据结构 从入门到进阶12学习笔记】红黑树_第14张图片

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 RBTree(){
        root = null;
        size = 0;
    }

    public int getSize(){
        return size;
    }

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

    // 判断节点node的颜色
    private 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;
    }

    //     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;
    }

    // 颜色翻转
    private void flipColors(Node node){

        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
    }

    // 向红黑树中添加新的元素(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 // key.compareTo(node.key) == 0
            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;
    }


最后

这里红黑树的实现方法只是其中一种,在算法导论中还有其他种实现方法,红黑树在统计性能上优于AVL树。

你可能感兴趣的:(算法,数据结构,java)