美文网首页
数据结构--红黑树

数据结构--红黑树

作者: Hayley__ | 来源:发表于2021-04-23 14:41 被阅读0次
2-3树
2-3树
  • 满足二分搜索树的基本性质
  • 节点可以存放一个元素或者两个元素
  • 每个节点可以有2个孩子(二节点) 或者3个孩子(三节点)
  • 绝对平衡的树(从根节点到任意一个叶子节点所通过的节点数量一定是相同的)
2-3树保持平衡

添加节点永远不会去空的节点,会和最后找到的叶子节点做融合。

添加12 添加2 添加4 添加4

红黑树

等价于2-3树

  • 保持黑平衡的二叉树,左右子树的黑色节点的高度差保持绝对平衡,2-3树本身是保持绝对平衡的
  • 每个节点或者是红色的,后者是黑色的
  • 根节点是黑色的
  • 每一个叶子节点(最后的空节点)是黑色的
  • 如果一个节点是红色,它的孩子节点都是黑色,黑色节点的右孩子一定是黑色的
  • 从任意一个节点出发到叶子节点,经过的黑色节点是一样的
  • 所有的红色节点向左倾斜
  • 最大高度:2logn
红黑树与2-3树
//红黑树基于二分搜索树
public class RedBlackTree <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;//因为在2-3树中添加的节点永远都是要融合到已有的节点中
        }
    }

    private Node root;
    private int size;

    public RedBlackTree(){
        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;
    }

    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 newValue) {
        Node node = getNode(root, key);
        if (node == null)
            throw new IllegalArgumentException(key + "doesn`t exist");
        node.value = newValue;
    }

}
添加元素相关操作
  • 左旋转,当添加的元素大于节点时,进行左旋转。(红色节点需要向左倾斜)
添加42
左旋转

左旋转代码

    //     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; //是2-3树中的三节点

        return x;
    }
  • 颜色翻转,添加66,因为42需要继续向上融合(向红黑树中的3节点添加元素)
添加66 颜色翻转

颜色翻转代码

    private void flipColors(Node node) {
        node.color = RED; //由于需要继续向上融合 所以是红色 
        node.left.color = Black;  // 三个二节点 是黑色
        node.right.color = Black; // 三个二节点 是黑色
    }
  • 右旋转,需要翻转颜色
添加12 右旋转 颜色翻转

右旋转代码

    //右旋转
    //        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;
    }
  • 先左旋转在右旋转在翻转颜色


    添加中间值元素
先左旋转 再右旋转 颜色翻转
添加元素过程总结
添加元素维护逻辑
    //向红黑树中添加元素
    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;
    }

性能总结

对于完全随机的数据,普通的二分搜索树很好用
缺点:极端情况下退化成链表(或者高度不平衡)
对于查询较多的使用情况,AVL树很好用
红黑树牺牲了平衡性(2logn的高度)
红黑树统计性能更优(综合增删改查所有的操作),平均性能优于AVL树。
数据结构中经常发生添加,删除的情况时,红黑树更合适。查询并不占优势。
如果数据近乎不会动的话,只查询,AVL树性能更好。

时间复杂度: O(logn)

相关文章

  • 数据结构红黑树添加、修改原理分析

    源码分析大纲 数据结构解析 红黑树试下原理刨析 数据结构解析 1.红黑树 1.1 红黑树概念 红黑树(Red Bl...

  • 数据结构 - 红黑树

    更多数据结构内容,请参考:数据结构 - 概要 简介 红黑树介绍请参考: 漫画:什么是红黑树? 面试旧敌之红黑树 红...

  • hashmap源码分析

    HashMap的数据结构 从上图中可以很清楚的看到,HashMap的数据结构是数组+链表+红黑树(红黑树since...

  • Red-Black Tree

    红黑树 前段时间看到STL map使用的数据结构是红黑树,研究了一下。 红黑树的由来 红黑树是二叉查找树的升级版本...

  • JDK1.8 之 集合框架 TreeMap TreeSet

    了解 Tree 之前我们必须了解 红黑树 因为Tree 的数据结构就是红黑树 红黑树的特性(1)每个节点或者是黑色...

  • 数据结构08-红黑树

    数据结构08-红黑树 一、红黑树的介绍 红黑树(RBT)是每个节点都带有颜色属性的自平衡二叉查找树,颜色或红色或黑...

  • 数据结构-红黑树学习笔记(转)

    rbt(红黑树) 图解红黑树:https://www.jianshu.com/p/0eaea4cc5619数据结构...

  • 2019-7-19

    部分常用容器类 HashMap 底层数据结构,数组 + 链表/红黑树链表类 - Node - 单链表 红黑树类 -...

  • java8中hashmap源码分析,put()方法详细分析

    一.源码大纲 1.了解红黑树原理(可翻看上一个文章,[红黑树原理分析](数据结构红黑树添加、修改原理分析 - 简书...

  • HashMap数据结构

    hashmap的数据结构由数组+链表+红黑树组成。

网友评论

      本文标题:数据结构--红黑树

      本文链接:https://www.haomeiwen.com/subject/vrnxrltx.html