【数据结构】红黑树

红黑树

思维导图

在这里插入图片描述

出现的背景,初衷,要解决的问题

背景:Rudolf Bayer在1972年发明了红黑树,称为“对称二叉B树”,但红黑树这个名字来源于Leo J Guibas 和 Robert Sedgewick在1978年写的一篇论文。

Rudolf Bayer是一名慕尼黑大学的信息学教授,(信息学是一门研究信息的收集、分类、操作、存储、检索和传播的科学),他发明红黑树的初衷是为了存储和有效地检索多维数据

简介:红黑树是一棵自平衡的二叉搜索树

应用场景:

1.C++中的map,set
2.Java中的HashMap,TreeMap,TreeSet
3.用于实现Linux中的CPU调度

优势和劣势

优势:

大多数地二叉搜索树检索信息的时间复杂度为O(h),h是二叉树的高,而且如果二叉树是一颗斜树,检索的时间复杂度会达到最差情况O(n),n是树的节点个数。
而红黑树检索的时间复杂度最多是O(logn)

劣势:

在插入,删除数据后需要进行调整平衡操作(染色,左旋,右旋)。
不适用于数据较少的场景

适用的场景

适用于海量数据,且需要经常进行插入删除操作的场景

类似的树和它的对比

AVL(平衡树)比起红黑树来说更加平衡,通俗的说就是查找性能可能更优;但平衡树在插入和删除时自旋的次数可能会大于红黑树,所以如果项目中插入删除节点操作更多选择红黑树会更好,如果查询操作更多则选择AVL树更好

底层原理,关键实现

源码

组成和关键点

红黑树节点需要遵守的规则

(满足以上规则的树大致是一个平衡树)

  • 1.每个节点是红的或者黑的
  • 2.根节点始终是黑的
  • 3.红节点均不相邻(一个节点的父节点和子节点不会为红)
  • 4.从任何节点(包括根节点)到达它子孙的NULL节点,经过的黑节点数相同

红黑树的一些特点

  • 1.三个节点的链在红黑树中是不存在的
  • 2.从一个节点到它最远叶子节点的节点数,不超过两倍到它最近叶子节点的节点数
  • 3.红黑树有n个节点,它的高h<=2log2(n+1)

黑高

  • 黑高是指从根节点到叶子节点经过的黑节点数(包含黑叶子节点)
  • 性质:黑高>=树高/2

保持平衡

  • 变色

    • 颜色由红变黑或由黑变红
  • 左旋

    • 以某个节点作为支点,它的右子节点变为它的父节点,右子节点的左节点变为它的左节点,右子节点的右节点不变
  • 右旋

    • 与左旋相反,类比即可

插入

  • 操作

    • 查找插入位置
    • 插入后的自平衡
  • 情景分析

    • 1.红黑树为空

      • 把插入节点作为根节点,并设置为黑
    • 2.插入节点key已存在

      • 用新节点value值覆盖旧的value
    • 3.插入节点的父节点为黑节点

      • 由于插入的节点是红色的,如果插入节点的父节点是黑色时,不会影响红黑树的平衡,直接插入即可,无需做自平衡调整
    • 4.插入节点的父节点为红色

      • 4.1叔叔节点存在并且为红

        • 由于不能存在两个相邻的红节点,所以祖父节点为黑;因此插入节点三代的颜色为:黑红红,显然最简单的处理方法就是将之变为:红黑红
        • 处理方法:
          1.先将父节点和叔叔节点变黑
          2.将祖父节点变红
          3.将祖父节点设置为当前节点,进行后续处理
        • 1.祖父节点在变色后是红色,如果祖父节点的父节点是黑色,那就不需要做任何处理
          2.如果祖父节点的父节点是红色,就违背了红黑树的性质:红色节点不能相邻;需要将祖父节点设置为当前节点,继续做自平衡操作
      • 4.2叔叔节点不存在或者为黑,并且插入节点的父节点是祖父节点的左子节点

        • 4.2.1新插入节点,为其父节点的左子节点(LL红色情况)

          • 处理:将祖父节点设为红,父节点设为黑,进行右旋
        • 4.2.2新插入节点,为其父节点的右子节点(LR红色情况)

          • 1.将父节点作为当前节点,进行左旋
            2.此时与4.2.1的情况相同(LL双红)将左旋后的父节点继续作为当前节点,按4.2.1处理
      • 4.3叔叔节点不存在或者为黑,插入节点的父节点是祖父节点的右子节点,与4.2对应

        • 4.3.1RR
        • 4.3.2RL

红黑树手写(含打印函数):

//红黑树类

/**
 * 1.创建RBTree,定义颜色
 * 2.创建静态内部类 RBNode
 * 3.辅助方法定义: parentOf(node), isRed(node), isBlack(node), setRed(node),setBlack(Node),InOrderPrint()
 * 4.左旋方法定义: leftRotate(node)
 * 5.右旋方法定义: rightRotate(node)
 * 6.公开插入接口方法定义: insert(K key, V value)
 * 7.内部插入接口方法定义: insert(RBNode node)
 * 8.修正插入导致红黑树失衡的方法定义: insertFixUp(RBNode node)
 * 9.测试红黑树的正确性
 *
 * @param <K>
 * @param <V>
 */
public class RBTree<K extends Comparable<K>, V> {
   

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

    // 打印红黑树
    public void padding ( String ch, int n )
    {
   
        int i;
        for ( i = 0; i < n; i++ )
            System.out.printf(ch);
    }
    void print_node (RBNode root, int level )
    {
   
        if ( root == null )
        {
   
            padding ( "\t", level );
            System.out.println( "NIL" );
        }
        else
        {
   
            print_node ( root.right, level + 1 );
            padding ( "\t", level );
            if(root.color == BLACK)
            {
   
                System.out.printf("(%d)\n", root.key );
            }
            else
                System.out.printf( "%d\n",root.key );
            print_node ( root.left, level + 1 );
        }
    }

    void print_tree()
    {
   
        print_node(this
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值