精华内容
下载资源
问答
  • 红黑树的结构和优势

    千次阅读 2019-03-30 16:24:49
    首先看一下红黑树的结构: 红黑树的结构特点: (1)每个节点或者是黑色,或者是红色。 (2)根节点是黑色。 (3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!] (4)如果...

    首先看一下红黑树的结构:

    在这里插入图片描述
    红黑树的结构特点:
    (1)每个节点或者是黑色,或者是红色。
    (2)根节点是黑色。
    (3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
    (4)如果一个节点是红色的,则它的子节点必须是黑色的。
    (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

    为什么要要用红黑树?
    1、首先红黑树是不符合AVL树的平衡条件的,即每个节点的左子树和右子树的高度最多差1的二叉查找树。但是提出了为节点增加颜色,红黑树是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。所以红黑树的插入效率更高

    2、红黑树能够以O(log2 (n)) 的时间复杂度进行搜索、插入、删除操作

    3、简单来说红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。

    红黑树和平衡树的对比和选择
    1、平衡树结构更加直观,读取性能比红黑树要高;增加和删除节点 恢复平衡的性能不如红黑树
    2、红黑树,读取性能不如平衡树;增加和删除节点 恢复平衡性能比平衡树好

    红黑树的使用场景:
    TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。

    展开全文
  • 红黑树

    千次阅读 多人点赞 2016-07-19 23:42:05
    红黑树

    红黑树

    1.      二叉树问题

    普通的二叉树作为数据存储工具有很大的优势,可以快速的插入、删除和查找数据项。遗憾的是,这仅仅是相对于插入随机数据,如果插入的数据是有序的,速度就变得特别慢了。

    2.      平衡树和非平衡树

    插入随机的数据,平衡树。

    插入有序的额数据,费平衡树。

    3.      红黑规则

    (1)      每个节点不是红色的就是黑色的。

    (2)      根总是黑色的。

    (3)      如果节点是红色的,则它的子节点必须是黑色的。

    (4)      从根节点到叶子节点的每条路径,必须包含相同的黑色节点。

    4.      纠正违规,将不符合红黑规则的树纠正为红黑树。

    (1)      改变节点的颜色。

    (2)      执行旋转操作。

    展开全文
  • 作用类似,但是比二叉平衡树更具有优势,会减少自平衡次数,实际应用中,也是使用红黑树,而不是二叉平衡树。 红黑树相对于二叉平衡树来说,牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要...

    红黑树与二叉平衡树比较

    红黑树与二叉平衡树(AVL树)一样,也是自平衡二叉排序树。作用类似,但是比二叉平衡树更具有优势,会减少自平衡次数,实际应用中,也是使用红黑树,而不是二叉平衡树。

    红黑树相对于二叉平衡树来说,牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于二叉平衡树

    红黑树定义

    红黑树特性:

    1. 每个节点要么红要么黑
    2. 根节点是黑色
    3. 每个叶子节点都是黑色(叶子是NULL节点表示 或 NIL节点表示)。
    4. 如果一个节点是红色的,那么它的子节点必须是黑色的子节点。(即不存在两个连续的红色节点)
    5. 从任一节点到其每个叶子结点(NULL节点或 NIL节点)的所有简单路径都包含相同数目的黑色节点。

    理解红黑树特性

    在这里插入图片描述
    【图一】理解1、2、3特性

    • 节点只有红黑两种颜色,如图所有节点,只有红黑
    • 根节点只能是黑色,如图80
    • 叶子节点都是黑色,如图NIL
      在这里插入图片描述
      【图二】理解4特性
    • 如果一个节点是红色的,那么它的子节点必须是黑色的子节点,如图40,子节点20/60都是黑色
      在这里插入图片描述

    【图三】理解4特性

    • 不可能存在两个连续的红色,但是可以存在连续的黑色,如图80/40/20
      在这里插入图片描述

    【图四】理解5特性

    • 从任一节点到其每个叶子结点(NULL节点或 NIL节点)的所有简单路径都包含相同数目的黑色节点。,如图节点80到任意NIL节点,路径都是3
      在这里插入图片描述

    【图五】理解5特性

    • 从任一节点到其每个叶子结点(NULL节点或 NIL节点)的所有简单路径都包含相同数目的黑色节点。如图节点100到任意NIL节点,路径都是2

    在这里插入图片描述
    【图六】理解5特性

    • 从任一节点到其每个叶子结点(NULL节点或 NIL节点)的所有简单路径都包含相同数目的黑色节点。性质5保证了以黑色节点为子树也是一颗红黑树,如图20为根节点子树

    通过上述6个图,我们基本上掌握的红黑树定义

    展开全文
  • 图解红黑树

    2019-02-02 09:35:45
    图解红黑树预先了解的知识什么是红黑树红黑树解决的问题红黑树的定义 预先了解的知识 二叉树 什么是红黑树 红黑树解决的问题  &amp...

    预先了解的知识

    • 二叉树

    什么是红黑树

    红黑树解决的问题

      在二叉树中,最坏的情况下,插入的数据类似一个链表。查找数据时就失去了二叉树的优势。平衡树就是用来解决这种情况的。红黑树就是平衡查找树的一种。
    举个例子:
      假设我们要插入字母A、B、C,按照顺序插入我们得到的二叉树是:
    在这里插入图片描述
    我们理想中的是要得到这样的:
    在这里插入图片描述
    那么我们要怎样做才能得到理想中的二叉树呢?方法之一就是红黑树。先简单的介绍一下红黑树A、B、C插入顺序的过程及发生的变化:
    在这里插入图片描述
    从上图可以看出,红黑树插入“A”,然后插入红色的“B”,然后对“A-B”进行了旋转。然后插入“C”得到了我们想要的平衡二叉树。这就是简单的红黑树的形成。

    红黑树的定义

    在此我们定义红黑树与《算法导论》中略有不同,不过也是等价的:

    • 红链接均为左链接;
    • 没有任何一个结点同时和两条红链接相连;
    • 该树是完美黑色平衡的,即任意空链接到根结点的路径上的黑链接数量相同。

    该定义出自《算法》。

    红链接:链接红色节点的链接。
    黑高:黑色节点的高度。
    我们的图片都大部分都省略了叶子结点的左右链接。空链接在这里我们定义成黑链接,也就是说叶子结点的左右链接都连接了黑节点。

    旋转与颜色转换

    旋转

    红黑树插入的新节点都是红色节点(根节点除外)。那么就会出现右节点为红色,或者连续两个左节点为红色的情况,而旋转就是为了处理这种情况:
    在这里插入图片描述

    左旋转,右旋转

    在这里插入图片描述

    颜色转换

    在插入的过程中还会出现,黑节点的左右节点都是红节点的情况,这就要通过颜色转换来处理:
    在这里插入图片描述颜色转换将,左右子树的红色纷纷提到父节点,将父节点变为红色,如果父节点是根节点,则父节点颜色要变成黑色,红黑树黑高加1 。

    插入

    为了方便表述这里增加几个定义:
    2-节点:就是普通的黑色节点,因为黑色节点必然右左右两个节点(可能都为null)。
    3-节点:一个黑色节点连接一个红色节点被称为3-节点。因为红黑树的高是黑高,所以红节点我们可以想象成跟黑节点在一起的,但是这个节点有三个子节点,如图:
    在这里插入图片描述插入的过程分为几种情况:

    • 对空树进行插入,即插入根节点
    • 对2-节点插入
      • 插入左节点
      • 插入右节点
    • 对3-节点插入
      • 插入左节点
      • 插入中间节点
      • 插入右节点

    对空节点进行插入是最简单的,直接插入就可以了。

    对2-节点插入

    对2-节点进行插入也比较简单,如果插入的是左节点,则不用进行任何调整;如果插入的是右节点,则进行左旋转就可以。

    对3-节点插入

    插入右节点

    如图插入“F”,这种情况直接进行颜色转换就可以:
    在这里插入图片描述

    插入左节点

    如图插入“B”,对"E"节点进行右旋转得到,再进行颜色转换就可以了:
    在这里插入图片描述

    插入中间节点

    如图插入“D”,对"C"进行左旋转,然后对“E"进行右旋转,再进行颜色转换就可以了:
    在这里插入图片描述

    删除

    在这里对3-节点进行拓展,既然有3-节点,那么自然就有4-节点、5-节点等。

    删除最小节点

    删除最小节点我们可以分为以下情况:

    • 删除的是2-节点
    • 删除的是3-节点

    删除的是3-节点

    删除3-节点分为两种情况:如果删除的是3-节点中的红色节点,那么直接删除就可以了。如果删除的是3-节点中的黑色节点,那么需要把黑色节点通过旋转变成红色节点再删除。

    删除的是2-节点

    凡是涉及到删除2-节点,都会涉及到红黑树的黑平衡。因此我们在从跟节点查找最小节点的过程中,可以从别地3-节点中借一个红色节点,并将红色节点顺移下去,使最小节点形成3-节点,这样就可以轻易删除。
    我们可以把红黑树分为下面几种情况:

    1. 向左查找的过程中,左边没有3-节点,右边也没有3-节点。
    2. 向左查找的过程中,左边没有3-节点,右边有3-节点。
    3. 向左查找的过程中,左边有3-节点。
      第一种情况我们要从父节点借,所以这就得保证我们的父节点一定是红色节点,所以从根节点开始,如果根节点的左右节点都不是3-节点,则直接将根节点置为红色,然后进行颜色转化。颜色转化之后树的高度减1,且树的平衡性得到保留,形成临时的4-节点:
      在这里插入图片描述第二种情况,要从右边的3-节点,“借”红色节点,使当前节点形成非2-节点,我们以跟节点为例(其余节点也是相同的操作):
      在这里插入图片描述
      第三种情况,树直接向下遍历就可以。通过反复的处理,就可以将最小的节点处理成红色节点。然后直接删除。删除之后还要向上进行遍历,将原来为了删除最小节点儿设置的不合理之处,重新恢复合理即可。

    删除随机节点

    删除随机节点,我们可以像删除最小节点一样一直向下遍历,直到找到要删除的节点。然后我们把要删除的节点的右子树中的最小节点赋值给我们要删除的节点,这样树中就没有了我们要删除的节点。但是却有两个一样数据的节点。因此我们将删除随机节点,成功的转化成了删除它的右子树中的最小节点。

    实现

    public class RedBlackBST<Key extends Comparable<Key>, Value> {
    
        private static final boolean RED   = true;
        private static final boolean BLACK = false;
    
        private Node root;     // 红黑树跟节点
    
        // 红黑树节点定义
        private class Node {
            private Key key;           // key
            private Value val;         // value
            private Node left, right;  // 左子树,右子树
            private boolean color;     // 节点颜色
            private int size;          // 节点数量
    
            public Node(Key key, Value val, boolean color, int size) {
                this.key = key;
                this.val = val;
                this.color = color;
                this.size = size;
            }
        }
    
    
    
        // 右旋转
        private Node rotateRight(Node h) {
            Node x = h.left;
            h.left = x.right;
            x.right = h;
            x.color = x.right.color;
            x.right.color = RED;
            x.size = h.size;
            h.size = size(h.left) + size(h.right) + 1;
            return x;
        }
    
        // 左旋转
        private Node rotateLeft(Node h) {
            Node x = h.right;
            h.right = x.left;
            x.left = h;
            x.color = x.left.color;
            x.left.color = RED;
            x.size = h.size;
            h.size = size(h.left) + size(h.right) + 1;
            return x;
        }
    
        // 颜色转换
        private void flipColors(Node h) {
            h.color = !h.color;
            h.left.color = !h.left.color;
            h.right.color = !h.right.color;
        }
    
    
        /**
         * 插入方法
         * @param key the key
         * @param val the value
         * @throws IllegalArgumentException
         */
        public void put(Key key, Value val) {
            if (key == null) throw new IllegalArgumentException("first argument to put() is null");
            if (val == null) {
                delete(key);
                return;
            }
    
            root = put(root, key, val);
            root.color = BLACK;
            // assert check();
        }
    
        // 插入方法
        private Node put(Node h, Key key, Value val) {
            if (h == null) return new Node(key, val, RED, 1);
    
            int cmp = key.compareTo(h.key);
            if      (cmp < 0) h.left  = put(h.left,  key, val);
            else if (cmp > 0) h.right = put(h.right, key, val);
            else              h.val   = val;
    
            // 插入完成后要将树进行转化
            if (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);
            h.size = size(h.left) + size(h.right) + 1;
    
            return h;
        }
    
    
        /**
         * 删除最小节点
         * @throws NoSuchElementException
         */
        public void deleteMin() {
            if (isEmpty()) throw new NoSuchElementException("BST underflow");
    
            if (!isRed(root.left) && !isRed(root.right))
                root.color = RED;
    
            root = deleteMin(root);
            if (!isEmpty()) root.color = BLACK;
        }
    
    
    
        // 删除最小节点
        private Node deleteMin(Node h) {
            if (h.left == null)
                return null;
    
            if (!isRed(h.left) && !isRed(h.left.left))
                h = moveRedLeft(h);
    
            h.left = deleteMin(h.left);
            return balance(h);
        }
    
    
        /**
         * 删除随机节点
         *
         * @param  key
         * @throws IllegalArgumentException
         */
        public void delete(Key key) {
            if (key == null) throw new IllegalArgumentException("argument to delete() is null");
            if (!contains(key)) return;
    
            if (!isRed(root.left) && !isRed(root.right))
                root.color = RED;
    
            root = delete(root, key);
            if (!isEmpty()) root.color = BLACK;
        }
    
        // 删除随机节点
        private Node delete(Node h, Key key) {
    
            if (key.compareTo(h.key) < 0)  {
                if (!isRed(h.left) && !isRed(h.left.left))
                    h = moveRedLeft(h);
                h.left = delete(h.left, key);
            }
            else {
                if (isRed(h.left))
                    h = rotateRight(h);
                if (key.compareTo(h.key) == 0 && (h.right == null))
                    return null;
                if (!isRed(h.right) && !isRed(h.right.left))
                    h = moveRedRight(h);
                if (key.compareTo(h.key) == 0) {
                    Node x = min(h.right);
                    h.key = x.key;
                    h.val = x.val;
                    h.right = deleteMin(h.right);
                }
                else h.right = delete(h.right, key);
            }
            return balance(h);
        }
    
        // 恢复平衡
        private Node balance(Node h) {
    
            if (isRed(h.right))                      h = rotateLeft(h);
            if (isRed(h.left) && isRed(h.left.left)) h = rotateRight(h);
            if (isRed(h.left) && isRed(h.right))     flipColors(h);
    
            h.size = size(h.left) + size(h.right) + 1;
            return h;
        }
    
        //检查该节点是否是红色节点
        private boolean isRed(Node x) {
            if (x == null) return false;
            return x.color == RED;
        }
    
        //子节点数量
        private int size(Node x) {
            if (x == null) return 0;
            return x.size;
        }
    
        /**
         * 检查该树是否为null
         * @return
         */
        public boolean isEmpty() {
            return root == null;
        }
    
    
        /**
         * 是否存在
         * @param key
         * @return
         * @throws IllegalArgumentException
         */
        public boolean contains(Key key) {
            return get(key) != null;
        }
    
        /**
         * 获取key对应的value
         * @param key
         * @return
         * @throws IllegalArgumentException
         */
        public Value get(Key key) {
            if (key == null) throw new IllegalArgumentException("argument to get() is null");
            return get(root, key);
        }
    
        // 获取key对应的value
        private Value get(Node x, Key key) {
            while (x != null) {
                int cmp = key.compareTo(x.key);
                if      (cmp < 0) x = x.left;
                else if (cmp > 0) x = x.right;
                else              return x.val;
            }
            return null;
        }
    
        // 从右边"借"红色节点
        private Node moveRedLeft(Node h) {
            flipColors(h);
            if (isRed(h.right.left)) {
                h.right = rotateRight(h.right);
                h = rotateLeft(h);
                flipColors(h);
            }
            return h;
        }
    
        // 从左边"借"红色节点
        private Node moveRedRight(Node h) {
            // assert (h != null);
            // assert isRed(h) && !isRed(h.right) && !isRed(h.right.left);
            flipColors(h);
            if (isRed(h.left.left)) {
                h = rotateRight(h);
                flipColors(h);
            }
            return h;
        }
        /**
         * 获取table的最小值
         * @return
         * @throws NoSuchElementException 
         */
        public Key min() {
            if (isEmpty()) throw new NoSuchElementException("calls min() with empty symbol table");
            return min(root).key;
        }
    
        // 获取当前节点的最小值
        private Node min(Node x) {
            // assert x != null;
            if (x.left == null) return x;
            else                return min(x.left);
        }
    
    
    
    
    }
    
    展开全文
  • 当然除HashMap还有很多地方都会用到红黑树,理解红黑树的原理还是比较重要的。* 2.概念与由来 红黑树的本质是二叉树,二叉树在插入元素的时候是根据关键字(可以理解为用来识别每个节点的id,...
  • 原文地址:...查了些资料,并且加上自己理解,感叹红黑树的巧妙。首先红黑树是不符合AVL树的平衡条件的,即每个节点的左子树和右子树的高度最多差1的二叉查找...
  • 手撕红黑树

    千次阅读 2020-06-19 00:53:19
    红黑树和2-3树是等价的,基于2-3树的红黑树是一种特殊的红黑树——左倾红黑树,我觉得基于2-3树来理解红黑树,比较好理解,毕竟红黑树的发明人Robert Sedgewick 在其经典著作《算法4》也是用2-3树来引入红黑树的。...
  • 学习红黑树

    2020-02-23 15:25:06
    红黑树归纳总结红黑树归纳总结参考文档基本概念红黑树定义和性质三种操作:左旋、右旋和变色红黑树核心思想深度颜色冲突红黑树查找红黑树插入深度颜色冲突情景4.1:情景4.2、4.3:小结红黑树删除1.SL SR都不存在2.SL...
  • 红黑树相关博客

    2021-04-07 09:24:59
    https://blog.csdn.net/weixin_39602615/article/details/111539094任何不平衡都可以在三次旋转内完成修复(红黑树的主要优势红黑树自身特性:https://segmentfault.com/a/1190000012728513 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,914
精华内容 7,165
关键字:

红黑树的优势