TreeMap的工作原理

本文介绍了红黑树的基本概念,包括其作为自平衡排序二叉树的特性。详细阐述了TreeMap在Java中的实现,包括如何通过put和deleteEntry方法进行节点的增删。讨论了插入时新节点始终保持红色,以及根据红黑树性质进行的左旋、右旋和着色操作。同时分析了delete()方法中删除节点的策略,如用子节点替代被删除节点并进行调整以保持红黑树的平衡。
摘要由CSDN通过智能技术生成
  • 红黑树的基本概念

  • 增加节点,删除节点的过程

  • 左旋转,右旋转的复杂过程

  • java中的TreeMap是如何通过put,deleteEntry两个来实现红黑树增加。删除节点的。
    基本概念

  • 红黑树首先是一颗二叉树,它具有二叉树的特性,同时红黑树更是一颗自平衡的排序二叉树。
    二叉树的特性:
    任何节点的值大于它的左节点且小于它的右节点,这样构建二叉树的过程很容易失去平衡,最坏的情况就是一边倒,这样导致对二叉树的检索效率大大降低(0(n)),所以为了维持二叉树的平衡,提出了红黑树。

平衡二叉树的特点

  • 它是一颗空树

  • 左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树。
    红黑树的特点:

  • 每个节点都只能是红色或是黑色。

  • 根节点是黑色

  • 每个叶节点是黑色的

  • 如果一个节点是红的,那它的两个子节点都是黑的,也就是说在一条路径不能出现相邻的两个红色节点。

  • 从任一节点到其每个叶子的所有路径包含相同数目的黑色节点。
    红黑树的三大特性:

  • 左旋

  • 右旋

  • 着色
    TreeMap的数据结构:

  • TreeMap继承AbstractMap,实现Navigable,Cloneable,Serializable三个接口。

  • AbstractMap表明TreeMap为一个Map,所以它支持key-value集合。

  • Navigable既支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法。
    为什么有序

  • 通过实现comparator接口我们可以对TreeMap的内部排序进行控制。
    重要属性:
    Entry是treemap的内部类
    size:容器大小
    modcount:修改的次数
    RED:节点的颜色-红色
    BLACK:节点的颜色-黑色
    Entry内部类的重要属性:

  • key 键

  • value 值

  • Entry<k,v> left=null 左孩子

  • Entry<k,v> rigth=nll 右孩子

  • Entry<k,v> parent 父亲

  • boolean color=BLACK 颜色
    TreeMap put()方法

  • 新节点插入的三个关键地方:

  • 插入节点总是红色节点

  • 如果插入节点的父节点是黑色的,能维持性质

  • 如果插入节点的父节点是红色的,破坏了性质,股插入算法就是通过重新着色或旋转来维持性质。
    实现步骤:

  • 为根节点:
    若插入的节点N没有父节点,则直接当做根节点即可,同时将严肃设为黑色。

  • 父节点为黑色
    这种情况下新节点N同样是直接插入,同时颜色为红色,这是他会存在两个褐色的叶子结点,值为null。由于新增节点为红色,所以通过它的子节点的路径依然会保存着相同的黑色节点数,满足规则5。
    在这里插入图片描述
    -若父节点p和p的兄弟节点U为红色。
    对于这种情况直接插入肯定出现不平衡现象。
    解决方法:p,u节点变黑,G节点变红,这时经过节点p,u的路径都必须经过G所以在这些路径上面的黑色节点数目还是相同的,但是这时G节点为红色的,这时我们需要将G节点当做新增节点递归处理。

在这里插入图片描述

  • 若父节点P为红色,叔父节点u为黑色或者缺少,且新增节点n为p节点的右孩子。
    解决:对新增节点n,p进行一次左旋转,产生的结果还是不平衡的,这时需进行情况5的操作。
    在这里插入图片描述

  • 父节点p为红色,叔父节点u为黑色或缺少,新增节点为父节点p左孩子。
    解决: 这种情况有可能是由于情况四而产生的,也有可能不是。对于这种情况先已P节点为中心进行右旋转,在旋转后产生的树中,节点P是节点N、G的父节点。但是这棵树并不规范,它违反了规则4,所以我们将P、G节点的颜色进行交换,使之其满足规范。开始时所有的路径都需要经过G其他们的黑色节点数一样,但是现在所有的路径改为经过P,且P为整棵树的唯一黑色节点,所以调整后的树同样满足规范5。
    在这里插入图片描述
    treeMap put()方法的分析:
    在TreeMap的put()的实现方法中主要分为两个步骤,第一:构建排序二叉树,第二:平衡二叉树。

    对于排序二叉树的创建,其添加节点的过程如下:
    
    1、以根节点为初始节点进行检索。
    
    2、与当前节点进行比对,若新增节点值较大,则以当前节点的右子节点作为新的当前节点。否则以当前节点的左子节点作为新的当前节点。
    
    3、循环递归2步骤知道检索出合适的叶子节点为止。
    
    4、将新增节点与3步骤中找到的节点进行比对,如果新增节点较大,则添加为右子节点;否则添加为左子节点。
    按照这个步骤我们就可以将一个新增节点添加到排序二叉树中合适的位置。如下:
    public V put(K key, V value) {
        //用t表示二叉树的当前节点
         Entry<K,V> t = root;
         //t为null表示一个空树,即TreeMap中没有任何元素,直接插入
         if (t == null) {
             //比较key值,个人觉得这句代码没有任何意义,空树还需要比较、排序?
             compare(key, key); // type (and possibly null) check
             //将新的key-value键值对创建为一个Entry节点,并将该节点赋予给root
             root = new Entry<>(key, value, null);
             //容器的size = 1,表示TreeMap集合中存在一个元素
             size = 1;
             //修改次数 + 1
             modCount++;
             return null;
        
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值