数据结构之红黑树Java实现

通俗易懂的图解二叉搜索树、AVL树和红黑树 搜索是一种很常见的需求,当数据较多时,如何找到目标对象时,即需要搜索查找。 那么如何快速找到目标呢,最朴素的思想就是暴力查找,一个一个对比。 显然,当数据量增大时,我们需要优化查找方法获取更快的查找速度,我们可以通过维护一个有序数组,从而实现二分查找,查找速度从O(n)降为O(longn)。 但是数组并不便于插入和删除,链表便成为了最好的选择。 既然是采用二分查找,那么不如直接按照查找的步骤维护一种数据结构,于是二叉搜索树出现了。 二叉搜索树的性质为: 若左子树不为空,则左子树上所有节点值都小于根结点值; 阅读详情

【本文是为了梳理知识的总结性文章,总结了一些自认为相关的重要知识点,只为巩固记忆以及技术交流,忘批评指正。其中参考了很多前辈的文章,包括图片也是引用,如有冒犯,侵删。】

1 红黑树的进化历程

1.1 第一阶段:树

树是一种常用的数据结构,它是一个由有限节点组成的一个具有层次关系的集合,数据就存在树的这些节点中。最顶层只有一个节点,称为根节点。在分支处有一个节点,指向多个方向,如果某节点下方没有任何分叉的话,就是叶子节点。从某节点出发,到叶子节点为止,最长简单路径上边的条数,称为该节点的高度;从根节点出发,到某节点边的条数,称为该节点的深度。

树结构的特点如下:
(1)一个节点,即只有根节点,也可以是一棵树。
(2)其中任何一个节点与下面所有节点构成的树称为子树。
(3)根节点没有父节点,而叶子节点没有子节点。
(4)除根节点外,任何节点有且仅有一个父节点。
(5)任何节点可以有0 ~ n个子节点。

1.2 第二阶段:二叉树

二叉树是指至多有两个子节点的树。二叉树具有以下几个性质:

  1. 二叉树中,第 i 层最多有 2 ^ (i-1) 个结点。
  2. 如果二叉树的深度为 K,那么此二叉树最多有 2^k - 1 个结点。
  3. 二叉树中,终端结点数(叶子结点数)为 n0,度为 2 的结点数为 n2,则 n0=n2+1。

二叉树,本质上,是对链表和数组的一个折中,数组的搜索比较方便,可以直接用下标,但删除或者插入某些元素就比较麻烦。  链表与之相反,删除和插入元素很快,但查找很慢。  结构良好的二叉就既有链表的好处,也有数组的好处。 

二分法是经典的问题拆解算法,二叉树是近似于二分法的一种数据结构实现,二叉树是高效算法实现的载体,在整个数据结构领域具有举足轻重的地位。在二叉树的世界中,最为重要的概念是平衡二叉树、二叉查找树、红黑树。

1.3 平衡二叉树

下图中左右两个都是树,但是左侧这颗树已经退化为了链表,有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本。而右侧是一棵平衡二叉树,能够最大地体现二叉树的优点。

平衡二叉树的性质如下:

  1. 树的左右高度差不能超过1。
  2. 任何往下递归的左子树与右子树,必须符合第一条性质。
  3. 没有任何节点的空树或只有根节点的树也是平衡二叉树。

1.4 二叉查找树

二叉查找树又称二叉搜索树,即Binary Search Tree,其中Search也可以替换为Sort,所以也称为二叉排序树。二叉查找树额外增加了如下要求:对于任意节点来说,它的左子树上所有节点的值都小于它,而它的右子树上所有节点的值都大于它。二叉查找树非常适合数据查找。

二又查找树由于随着数据不断地增加或删除容易失衡,需要保持二叉树的平衡性,有很多算法的实现,如AVL树、红黑树、SBT(Size Balanced Tree)、Treap(树堆)等。

1.5 AVL 树

AVL树算法是以苏联数学家Adelson-Velsky和Landis名字命名的平衡二叉树算法,可以使二叉树的使用效率最大化。AVL树是一种平衡二叉查找树,增加和删除节点后通过树形旋转重新达到平衡。右旋是以某个节点为中心,将它沉入当前右子节点的位置,而让当前的左子节点作为新树的根节点,也称为顺时针旋转;同理,左旋是以某个节点为中心,将它沉入当前左子节点的位置,而让当前右子节点作为新树的根节点,也称为逆时针旋转。查找、插入和删除在平均和最坏情况下的时间复杂度都是O(\log{n})。增加和删除元素的操作则可能需要借由一次或多次旋转,以实现树的重新平衡。

 

2 红黑树

红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它在1972年由鲁道夫·贝尔发明,被称为"对称二叉B树",1978年得到优化,正式命名为红黑树。它的主要特征是在每个节点上增加一个属性来表示节点的颜色,可以是红色,也可以是黑色。红黑树的结构复杂,但它的操作有着良好的最坏情况运行时间,并且在实践中高效:{\displaystyle {\text{O}}(\log n)}时间内完成查找,插入和删除,这里的n是树中元素的数目。

红黑树和AVL树类似,都是在进行插入和删除元素时,通过特定的旋转来保持自身平衡的,从而获得较高的查找性能。与AVL树相比,红黑树并不追求所有递归子树的高度差不超过1,而是保证从根节点到叶子节点的最长路径不超过最短路径的2倍,所以它的最坏运行时间也是{\displaystyle {\text{O}}(\log n)}。红黑树通过重新着色和左右旋转,更加高效地完成了插入和删除操作后的自平衡调整。当然,红黑树在本质上还是二叉查找树,它额外引入了5个约束条件:

  1. 节点只能是红色或黑色。
  2. 根节点必须是黑色。
  3. 所有NIL节点都是黑色的。NIL,即叶子节点下挂的两个虚节点。
  4. 一条路径上不能出现相邻的两个红色节点。
  5. 在任何递归子树内,根节点到叶子节点的所有路径上包含相同数目的黑色节点。

An example of a red-black tree

总结一下,即“有红必有黑,红红不相连”。如果一个树的左子节点或右子节点不存在,则均认定为黑色。红黑树的任何旋转在3次之内均可完成。

// 使用boolean值表示红黑树节点颜色
    private static final boolean RED   = false;
    private static final boolean BLACK = true;
    
    static final class Entry<K,V> implements Map.Entry<K,V> {
        K key;              
        V value;
        Entry<K,V> left;    // 左子树
        Entry<K,V> right;   // 右子树
        Entry<K,V> parent;  // 父节点
        boolean color = BLACK; // 节点颜色

        Entry(K key, V value, Entry<K,V> parent) {
            this.key = key;
            this.value = value;
            this.parent = parent;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;

            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
        }

        public int hashCode() {
            int keyHash = (key==null ? 0 : key.hashCode());
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        }

        public String toString() {
            return key + "=" + value;
        }
    }

3 红黑树的基本操作

下面安装TreeMap的红黑树实现进行介绍:

左旋

private void rotateLeft(Entry<K,V> p) {
        // 如果 p 不是NULL节点
        if (p != null) {
     
            Entry<K,V> r = p.right;
            // 将r的左子树设置为p的右子树
            p.right = r.left;
            // 如果r的左子树不为空,则将p设置为r左子树的父亲
            if (r.left != null)
                r.left.parent = p;
            // 将p的父亲设置为r的父亲
            r.parent = p.parent;
            
            if (p.parent == null)
                root = r;
            else if (p.parent.left == p)
                p.parent.left = r;
            else
                p.parent.right = r;
            r.left = p;
            p.parent = r;
        }
    }

右旋

private void rotateRight(Entry<K,V> p) {
        if (p != null) {
            Entry<K,V> l = p.left;
            p.left = l.right;
            if (l.right != null) l.right.parent = p;
            l.parent = p.parent;
            if (p.parent == null)
                root = l;
            else if (p.parent.right == p)
                p.parent.right = l;
            else p.parent.left = l;
            l.right = p;
            p.parent = l;
        }
    }

查找

 final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
            Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left; // 当前元素大于目标元素,向左找
            else if (cmp > 0)
                p = p.right; // 当前元素小于目标元素,向右找
            else
                return p;
        }
        return null;
    }

插入

插入新节点后,可能会导致树不满足红黑树性质,这时就需要对树进行旋转操作和重新着色进行修复,使得它符合红黑树的定义。在插入新节点前,需要明确三个前提条件:

  1. 新插入的节点总是红色的;
  2. 如果新节点的父节点是黑色,则不需要进行修复;
  3. 如果新节点的父节点是红色,因为红黑树规定不能出现相邻的两个红色节点,需要进行修复。

插入修复时可能碰到的情况可分为的三种:

  1. 叔叔节点也为红色。
  2. 叔叔节点为空,且爷爷节点、父节点和新节点处于一条斜线上。
  3. 叔叔节点为空,且爷爷节点、父节点和新节点不处于一条斜线上。

每一种情况根据新节点的父节点是爷爷节点的左侧还是右侧可以分为两种情况,所以可以细分为6种情况。

第一种情况处理方法:

因为新节点、父节点、叔叔节点都是红色,爷爷节点是黑色,因此通过局部颜色调整,就可以使子树继续满足红黑树的性质。将父节点和叔叔节点置为黑色,爷爷节点置为红色。然后再以爷爷节点为新节点进行下一轮调整,直到满足红黑树性质为止。

第二种情况处理方法:

将新节点的父节点置为黑色,爷爷节点置为红色。如果父节点在爷爷节点左侧,则对父节点进行右旋操作。如果父节点在爷爷节点右侧,则对父节点进行左旋操作。

第三种情况处理方法:

将不在一条直线上的节点调整为直线,如果父节点在爷爷节点左侧,则对父节点进行左旋操作。如果父节点在爷爷节点右侧,则对父节点进行右旋操作。变成第二种情况,然后再进行旋转操作。

代码

private void fixAfterInsertion(Entry<K,V> x) {
		// 新节点为红色
        x.color = RED;

        while (x != null && x != root && x.parent.color == RED) { // 循环调整
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                	// 第一种情况,父节点在爷爷节点左侧
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                	
                    if (x == rightOf(parentOf(x))) {
                    // 第三种情况,父节点在爷爷节点左侧 
                        x = parentOf(x);
                        rotateLeft(x);
                    }
                    // 第二种情况,父节点在爷爷节点左侧
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                }
            } else {
            	 
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) {
                	// 第一种情况,父节点在爷爷节点右侧
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                } else {
                    if (x == leftOf(parentOf(x))) {
                    	// 第三种情况,父节点在爷爷节点右侧
                        x = parentOf(x);
                        rotateRight(x);
                    }
                    // 第二种情况,父节点在爷爷节点右侧
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                }
            }
        }
        // 根节点为黑色
        root.color = BLACK;
    }

删除

因为删除RED节点不会破坏红黑树的任何约束,而删除BLACK节点会破坏规则4,因此只有删除节点是BLACK的时候,才会触发调整函数。删除修复操作是针对删除黑色节点才有的。

删除BLACK节点后的修复操作分为四种情况:

  1. 待删除的节点的兄弟节点是红色的节点。
  2. 待删除的节点的兄弟节点是黑色的节点,且兄弟节点的子节点都是黑色的。
  3. 待调整的节点的兄弟节点是黑色的节点,且兄弟节点的左子节点是红色的,右节点是黑色的(兄弟节点在右边),如果兄弟节点在左边的话,就是兄弟节点的右子节点是红色的,左节点是黑色的。
  4. 待调整的节点的兄弟节点是黑色的节点,且右子节点是是红色的(兄弟节点在右边),如果兄弟节点在左边,则就是对应的就是左节点是红色的。

每一种情况根据删除节点是父节点的左侧还是右侧可以分为两种情况,所以可以细分为8种情况。

第一种情况处理方法:

由于兄弟节点是红色节点的时候,无法借调黑节点,所以需要将兄弟节点提升到父节点。因为兄弟节点是红色的,无法借到一个黑节点来填补删除的黑节点。兄弟节点是红色,其子节点是黑色的,可以从它的子节点借调。提升操作需要对兄弟节点做一个左旋操作,如果是镜像结构的树只需要做对应的右旋操作即可。

第二种情况处理方法:

由于兄弟节点以及其子节点都是黑色的,可以消除一个黑色节点,这样就可以保证树的局部的颜色符合定义了。这个时候需要将父节点变成新的节点,继续向上调整,直到整颗树的颜色符合红黑树的定义为止。这种情况下之所以要将兄弟节点变红,是因为如果把兄弟节点借调过来,会导致兄弟的结构不符合红黑树的定义,这样的情况下只能是将兄弟节点也变成红色来达到颜色的平衡。当将兄弟节点也变红之后,达到了局部的平衡了,但是对于祖父节点来说是不符合定义4的。这样就需要回溯到父节点,接着进行修复操作。

第三种情况处理方法:

第三种情况是一个中间步骤,它的目的是将左边的红色节点借调过来,这样就可以转换成第四种情况进行处理。

第四种情况处理方法:

是真正的节点借调操作,通过将兄弟节点以及兄弟节点的右节点借调过来,并将兄弟节点的右子节点变成红色来达到借调两个黑节点的目的,这样的话,整棵树还是符合RBTree的定义的。这种情况的发生只有在待删除的节点的兄弟节点为黑,且子节点不全部为黑,才有可能借调到两个节点来做黑节点使用,从而保持整棵树都符合红黑树的定义。

private void fixAfterDeletion(Entry<K,V> x) {
    while (x != root && colorOf(x) == BLACK) {
        if (x == leftOf(parentOf(x))) {
            Entry<K,V> sib = rightOf(parentOf(x));
            if (colorOf(sib) == RED) {
                setColor(sib, BLACK);                   // 情况1
                setColor(parentOf(x), RED);             // 情况1
                rotateLeft(parentOf(x));                // 情况1
                sib = rightOf(parentOf(x));             // 情况1
            }
            if (colorOf(leftOf(sib))  == BLACK &&
                colorOf(rightOf(sib)) == BLACK) {
                setColor(sib, RED);                     // 情况2
                x = parentOf(x);                        // 情况2
            } else {
                if (colorOf(rightOf(sib)) == BLACK) {
                    setColor(leftOf(sib), BLACK);       // 情况3
                    setColor(sib, RED);                 // 情况3
                    rotateRight(sib);                   // 情况3
                    sib = rightOf(parentOf(x));         // 情况3
                }
                setColor(sib, colorOf(parentOf(x)));    // 情况4
                setColor(parentOf(x), BLACK);           // 情况4
                setColor(rightOf(sib), BLACK);          // 情况4
                rotateLeft(parentOf(x));                // 情况4
                x = root;                               // 情况4
            }
        } else { // 跟前四种情况对称
            Entry<K,V> sib = leftOf(parentOf(x));
            if (colorOf(sib) == RED) {
                setColor(sib, BLACK);                   // 情况5
                setColor(parentOf(x), RED);             // 情况5
                rotateRight(parentOf(x));               // 情况5
                sib = leftOf(parentOf(x));              // 情况5
            }
            if (colorOf(rightOf(sib)) == BLACK &&
                colorOf(leftOf(sib)) == BLACK) {
                setColor(sib, RED);                     // 情况6
                x = parentOf(x);                        // 情况6
            } else {
                if (colorOf(leftOf(sib)) == BLACK) {
                    setColor(rightOf(sib), BLACK);      // 情况7
                    setColor(sib, RED);                 // 情况7
                    rotateLeft(sib);                    // 情况7
                    sib = leftOf(parentOf(x));          // 情况7
                }
                setColor(sib, colorOf(parentOf(x)));    // 情况8
                setColor(parentOf(x), BLACK);           // 情况8
                setColor(leftOf(sib), BLACK);           // 情况8
                rotateRight(parentOf(x));               // 情况8
                x = root;                               // 情况8
            }
        }
    }
    setColor(x, BLACK);
}

 

4 红黑树与AVL树的比较

先从复杂度分析说起,任意节点的黑深度(Black Depth)是指当前节点到NIL(树尾端)途径的黑色节点个数。根据约束条件的第(4)、(5)条,可以推出对于任意高度的节点,它的黑深度都满足:Black Depth ≥ height / 2。也就是说,对于任意包含n个节点的红黑树而言,它的根节点高度h ≤ 2log2(n+1)。常规BST操作比如查找、插入、删除等,时间复杂度为O(h),即取决于树的高度h。当树失衡时,时间复杂度将有可能恶化到O(n),即h = n。所以,当我们能保证树的高度始终保持在O(logn)时,便能保证所有操作的时间复杂度都能保持在O(logn)以内。

红黑树的平衡性并不如AVL树,它维持的只是一种大致上的平衡,并不严格保证左右子树的高度差不超过1。这导致在相同节点数的情况下,红黑树的高度可能更高,也就是说,平均查找次数会高于相同情况下的AVL树。在插入时,红黑树和AVL树都能在至多两次旋转内恢复平衡。在删除时,由于红黑树只追求大致上的平衡,因此红黑树能在至多三次旋转内恢复平衡,而追求绝对平衡的AVL树,则至多需要O(logn)次旋转。AVL树在插入与删除时,将向上回溯确定是否需要旋转,这个回溯的时间成本最差可能为O(logn),而红黑树每次向上回溯的步长为2,回溯成本降低。因此,面对频繁的插入和删除,红黑树更为合适;面对低频修改、大量查询时,AVL树将更为合适。

 

参考文献

  1. http://data.biancheng.net/view/192.html
  2. https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91
  3. https://tech.meituan.com/2016/12/02/redblack-tree.html
  4. https://github.com/CarpenterLee/JCFInternals/blob/master/markdown/5-TreeSet%20and%20TreeMap.md
  5. https://www.zhihu.com/question/37381035
  6. 《码出高效:Java开发手册》
Java集合框架底层数据结构:从动态数组到红黑树,深入理解实现原理 深入解析List、Set、Queue、Map四大接口的常用实现类的底层实现,帮助零基础读者彻底掌握集合框架的设计逻辑。作为Java开发者,持续输出技术总结是提升能力的关键。无论你是初学Java的新手,还是希望巩固基础的中级开发者,本文都将成为你的集合类“速查手册”📚。| Java集合框架的每个类都有其独特的底层数据结构,这些结构直接影响集合的。理解集合类的底层数据结构,是写出高性能Java代码的关键。增删快但查询慢,其本质区别源于底层是数组还是链表。,获取更多Java学习和开发干货! 阅读详情

相关推荐

数据结构系列之Java手写实现红黑树

数据结构系列之Java手写实现红黑树,红黑树是一种自平衡的二叉搜索树,是二叉搜索树的拓展。红黑树只有两种节点,一种是红色的,一种是黑色的。红黑树不像AVL树那样严格,而是近似平衡。

Nicky's blog 3376

Java高阶数据结构之红黑树

本文是Java高阶数据结构的学习,剖析红黑树底层原理,红黑树的时间复杂度,红黑树的插入以及插入时的平衡调整。之后的学习内容将持续更新!!!

qq15035899256的博客 3724

什么是PMOS?什么是NMOS?两者有什么区别?

这个电压差被称为阈值电压(Vth),通常为0.7V至2V(低压NMOS)或4V至10V(功率NMOS)。当Vgs(栅极-源极电压)大于Vth时,沟道中的电子被吸引到栅极下方,形成导电通路,使电流可以从漏极流向源极。NMOS与PMOS的结构类似,都由三大部分组成:栅极(Gate)、源极(Source)和漏极(Drain)。由于NMOS在开启时,电子是主要的载流子,电子的迁移率比空穴高,因此NMOS通常具有更低的导通电阻(Rds(on)),这使其成为高速开关电路中的首选。它的沟道由电子(负载子)传导。

硅农深芯的博客 6430

Java实现红黑树数据结构

手写红黑树,java数据结构

weixin_60523038的博客 1549

用 dism 合并与删除 wim 映像

一、合并 假设 installA.wim 有 3 个映像,installB.wim 有 1 个映像。 1、全部合并 将 installA.wim 中的 3 个卷映像合并到 installB.wim 中,这样 installB.wim 中的卷映像增加到 4 个。 dism/export-image/sourceimagefile:d:\installA.wim/sourceindex:1/destinationimagefile:d:\installB.wim dism/export-image/source

KefanWon的博客 5198

Ubuntu升级遇到grub-efi-amd64-signed安装失败?3步搞定这个烦人错误

本文深度解析Ubuntu系统升级时grub-efi-amd64-signed安装失败并提示“cannot find EFI directory”错误的根本原因。该错误通常由EFI系统分区挂载异常、BIOS/UEFI引导模式不匹配或dpkg包状态死锁导致。文章提供了三步精准修复流程:首先检查并修复ESP分区挂载,其次处理dpkg依赖问题,最后针对传统BIOS系统提供适配方案,帮助用户安全彻底地解决这一常见升级难题。

r7s8t的博客 397

Java数据结构——树——红黑树

插入节点 新插入的节点颜色默认为红色 如果新插入节点的父节点颜色为红色 违反了性质4 1.新插入节点的父节点为其父节点的左子节点时,找到其叔叔节点 1.1 如果叔叔节点的颜色为红色时 1.1.1将插入节点的父节点和叔叔节点的颜色设置为黑色,并且将插入节点的祖父节点的颜色设置为红色,再将祖父节点设置为插...

qq_41770939的博客 1083

使用 pip 安装 pygame 遇到的问题

今天尝试学习使用 pygame 时,按照我的习惯一发 pip install 下去,本以为很简单的事情,没想到遇到了不少问题,顺手记录一下。 0x01. 无法找到 “SDL.h” 文件 pygame 是使用 SDL 库写就的游戏框架,自然强依赖于 SDL,我的 python@3 是使用 macOS 的 brew 管理器直接安装的,可能由于不是编译安装的问题,缺少了这个库,继续使用 brew 安...

Mitscherlich的博客 8620

树形数据结构-红黑树:原理诠释,附Java实现示例

红黑树是一种广泛使用的自平衡二叉搜索树的具体实现。在 JDK 中,它用于TreeMap中,从 Java 8 开始,它也用于HashMap中的bucket碰撞。它到底是如何工作的呢?什么是红黑树?如何将元素插入红黑树?如何移除它们?平衡红黑树的规则是什么?如何在Java中实现红黑树?它的时间复杂度如何确定?红黑树与其他数据结构有何区别?2. 什么是红黑树?红黑树是一种自平衡二叉搜索树,即能自动保持某种平衡的二叉搜索树。每个节点都分配有一种颜色(红色或黑色)。

在技术的广袤天地里,本博客如精准罗盘。剖析前沿科技,深掘代码奥秘,以精炼笔触,带您穿越复杂技术迷宫,速达知识彼岸。 2095

激光雷达点云异常现象详解:鬼影、高反膨胀与拖点

现象核心外观主要成因核心硬件对策核心算法对策鬼影位置错误,出现"复制"的物体镜面反射/光学元件间杂散光物理光阑、抗反射涂层多帧时序一致性检验、反射率逻辑判断膨胀尺寸变大,轮廓呈毛刺状信号饱和、像素/通道串扰可变增益控制、随机编码序列强度阈值滤波、几何轮廓拟合(剪裁)拖点边缘粘连,出现"阶梯"或"连线"光斑跨立边缘、双回波融合小光斑光学设计、多回波支持邻域深度突变检测、波形脉宽分析这些异常现象是当前激光雷达感知中的核心难点,通常需要硬件物理特性优化与上层感知算法。

Fun_LiDAR的博客 299

PDAF相位对焦原理

pdaf光路图

camerall 1万+

【数据结构与算法】JAVA实现自定向下的红黑树

文章目录JAVA实现自定向下的红黑树红黑树红黑树 的特点代码实现 JAVA实现自定向下的红黑树 主要是记录自己的内容,具体原理可能不够详细,代码可以参考。 红黑树 红黑树是AVL树的一种流行的变种。 红黑树的操作再最坏的情况下花费O(logN)的时间 参考:参考:《数据结构与算法分析:JAVA语言描述》P362 红黑树的插入、删除操作都较为复杂,本代码已实现插入操作,但书上的删除操作虽然看起来简单,但实在难以实现,网上的删除操作资料过于复杂(需大量分类讨论)。如有大佬有较为简洁的实现方式,不吝赐教。 红黑树

大枫树 195

使用CloudCompare和CANUPO进行点云分类的编程指南

在本文中,我们将介绍如何使用CloudCompare和CANUPO库进行点云分类的编程。CloudCompare是一款功能强大的开源点云处理软件,而CANUPO是一个用于点云分类和分割的C++库。这只是一个简单的点云分类示例,CANUPO库还提供了其他更高级的功能和算法,以满足各种点云分类需求。该函数接受点云数据、地面点掩码和非地面点掩码作为输入,并将分类结果存储在这两个掩码向量中。完成安装后,我们可以开始编写点云分类的代码。最后,我们遍历点云数据,并根据地面点和非地面点的掩码将结果打印出来。

ByteWhisper的博客 1058

Java 数据结构篇-实现红黑树的核心方法

手撕红黑树,实现红黑树的更新、添加与删除等核心方法! 红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是红色或黑色。与 AVL 树相比之下,红黑树放宽了对平衡的要求,通过牺牲一定的平衡性能来换取更高的插入、删除和查找操作的性能。红黑树的旋转操作相对较少,因此在实际应用中,红黑树更常用于需要高效的动态数据结构,如集合、映射等。而 AVL 树则更适用于对平衡性要求较高的场景,如数据库索引等。总的来说,红黑树也是一种自平衡的二叉搜索树。

小扳手 6377

CPU、Core、RISC、ARM等的前世今生

CPU、Core、RISC-V 、ARM、ASIC、FPGA、SOC概念及区分

nxin168的博客 1013

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

终极Java数据结构指南:从链表到红黑树的实现与原理

CodeGuide是小傅哥多年一线互联网Java开发经验的技术汇总,为开发者提供清晰详细的Java核心内容学习教程。本文将带您深入探索数据结构的世界,从基础的链表到复杂的红黑树,掌握这些核心数据结构的实现原理与应用场景。 ## 为什么数据结构对Java开发者如此重要? 在计算机科学中,数据结构是程序设计的基础。一个优秀的Java开发者不仅要会使用API,更要理解其背后的数据结构原理。正如小傅哥

gitblog_00107的博客 930

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

数据结构-红黑树-java实现红黑树

什么是红黑树? 红黑树为一种特殊的二叉查找树,但相较于二叉查找树,红黑树自平衡的二叉查找树。 红黑树和二叉平衡树的区别 1、红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单。 2、平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知。 所以红黑树有着比二叉平...

weixin_44462294的博客 718

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

【数据结构】java实现红黑树

红黑树五个性质(可以参考维基百科) 节点是红色或者黑色 根节点是黑色 叶子节点颜色为黑色(不是NULL节点,是自己构造的黑色叶子结点) 红色节点的孩子节点是黑色 从某个节点到其叶子结点的黑色节点个数相同 红黑树的插入和删除操作就是为了保证这五个性质,特别是性质4、5。因此,为了保证插入不破坏性质5,插入时节点颜色默认为红色 红黑树节点数据结构 package com.xll.tree.re...

xia744510124的专栏 206

数据结构与算法【红黑树】的Java实现+图解

红黑树也是一种自平衡的二叉搜索树,较之 AVL,插入和删除时旋转次数更少。首先介绍代码实现会用到的概念兄弟节点:具有同一个父结点的一对节点可以互称为兄弟节点叔叔节点:父结点的兄弟节点。

zmbwcx的博客 1909

JAVA数据结构与算法(八)java实现红黑树

JAVA数据结构与算法(八)java实现红黑树 红黑树的性质 红黑树是一种自平衡二叉树,红黑树和AVL树一样都对插入时间、删除时间和查找时间提供了最好可能的最坏情况担保。 红黑树需要满足的五条性质: 性质一:节点是红色或者是黑色; 在树里面的节点不是红色的就是黑色的,没有其他颜色。 性质二:根节点是黑色; 根节点总是黑色的。它不能为红。 性质三:每个叶子节点是黑色。 [注意:这里叶子节点,是指为空...

Tong_Nan的博客 3405

Java 中常见数据结构之哈夫曼树、红黑树、B + 树和跳表详解及手撕代码实现

在 Java 编程中,数据结构的选择对于程序的性能和效率至关重要。本文将详细介绍哈夫曼树、红黑树、B + 树和跳表这四种常见的数据结构,并提供 Java 代码实现及解析。

m0_57836225的博客 1235

如何在Java中实现高效的树状数据结构:从红黑树到B+树

红黑树在插入和删除操作上具有较高的效率,而B+树则更适合用于存储和检索大量数据的场景。在计算机科学中,树状数据结构是一种非常重要的数据组织方式,特别是在数据库和文件系统中,红黑树和B+树是两种广泛应用的树状数据结构。本文将介绍如何在Java中高效地实现红黑树和B+树,并展示这些数据结构在实际应用中的优势。插入操作涉及到对节点的分裂和数据的重新分配,以确保B+树的平衡性和高效性。红黑树是一种自平衡二叉搜索树,它在插入和删除操作后通过调整节点的颜色和树的结构来保持平衡,确保树的高度为。,在实际应用中非常高效。

微赚淘客系统开发者博客 525

Java实现数据结构——红黑树删除

本文参考《算法导论(第三版)》和JDK1.8-HashMap源码 回顾红黑树基本性质 每个节点或是红色,或是黑色 根节点是黑色 每个叶节点是黑色 如果一个节点是红色,那么它的两个子节点都是黑色 对于每个节点,从该节点到其所有后代叶节点的简单路径上,包含相同数目的黑色节点 删除节点 节点的基本删除操作:二叉查找树-删除元素 《算法导论(第三版)》中的二叉查找树的删除操作原理是,...

x_k的专栏 1620

【数据结构】红黑树Java实现

【数据结构】红黑树Java实现

qq_41403171的博客 622

Java数据结构:红黑树的原理与完整实现

红黑树是一种特殊的二叉搜索树,每个节点都带有颜色属性(红色或黑色)。通过对节点颜色的约束,红黑树确保从根到叶子的最长路径不会超过最短路径的2倍,从而保持树的平衡。/*** 红黑树节点类*/T data;// 数据// 左子节点// 右子节点// 父节点// 颜色:true表示红色,false表示黑色// 颜色常量// 新插入的节点默认为红色@Override插入策略新节点始终插入为红色根节点必须是黑色通过旋转和重新着色维护平衡删除策略。

weixin_73735141的博客 910

红黑树数据结构讲解(附Java实现代码)

2-3查找树定义 1.任意空链接到根节点的路径长度都是相等的 2. 4-结点变换为3-结点时, 树的高度不会发生变化, 只有当根节点是临时的4-结点时, 分解根节点后, 树的高度+1 3.普通二叉查找树是自顶向下生长的, 2-3查找树的自底向上生长的 都是2-3查找树 (插入节点过程中产生的4-结点是临时的!) 红黑树定义 在满足2-3查找树的前提上, 使用对结点间链接的==“标记” == 以 颜色有两种: 红色 模拟2-3查找树中的3-结点 黑色 普通的结点链接形式 性质: 红链接均为左连接 2

Valishment的博客 428
上一篇: JDK 8 HashSet 源码解析
下一篇: 计算无线信号的传输距离
TaiSung
博客等级 码龄15年 49粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值