红黑树键值对 -- TreeMp

一:概述

Collection系列的List与Set实现都只能存储单个元素,想要使用 key – value 的结构就需要使用到Map。整体来说Map的实现结构并不复杂,三个具体实现类TreeMap、HashMap、LinkedHashMap,分别采用红黑树、哈希表、链表 + 哈希表的结构实现。本文将讲解采用红黑树实现的TreeMap,红黑树结构注定这将是一个元素拥有一定比较顺序的集合

二:继承结构

在这里插入图片描述

三:红黑树实现

在这里插入图片描述
静态内部类Entry其实就是红黑树的节点类。key、value属性记录节点值,left、right、parent分别记录左右节点与父节点,color则记录节点颜色,红与黑。说到这里如果不了解红黑树的请自行查阅相关书籍,算法导论就不错嘛。基础有以下几点特征:

  • 根节点必须是黑色
  • 红节点上下必须是黑色,也就是它的父亲与儿子
  • 任意节点通过任意路径到叶子节点中黑节点的累计数量相等
四:比较器

在这里插入图片描述
看一下TreeMap类的属性发现除了root维护红黑树根节点之外还有一个比较器comparator,这个比较器自然就是定义节点元素大小规则的比较器。在元素节点插入的时候会使用

4.1 构造注入

在这里插入图片描述
实例化对象的时候可以传递Comparator类型比较器,这时就会将其赋值给属性comparator。注意泛型限制的咯,这个K是TreeMap中key键的泛型,比较器要求是其父类亦或是自身,满足里氏替换原则设计要求

4.2 默认比较器

在这里插入图片描述
如果是无参构造那就比较惨烈了,比较器就是一个null。那么元素节点新增的时候就不用了么?默认的比较器肯定是存在的嘛,看看下图
在这里插入图片描述
这个比较方法就是在需要使用到比较器调用的比较方法,三目表达式规定如果有比较器就用,没有就用key值调用compareTo()。所以,敲黑板咯,存储到TreeMap的元素要么提供Compartator比较器,要么自身实现Comparable接口。不然这个强转可以错的一塌糊涂

五:红黑树左右旋转

在涉及到节点新增或删除的时候就有可能导致红黑树特征被破坏,这时候就需要调整红黑树重新形成红黑树特征结构。要么选择改变节点颜色,要么选择红黑树结构调整。左右旋就是红黑树结构调整中基础的两个方法

5.1 红黑树左旋

在这里插入图片描述
红黑树的左旋其实就是以旋转节点为中心的逆时针顺序旋转,最后效果如上图所示。总结起来就两点:
1、旋转节点右节点成为其父节点
2、 右节点的左节点给旋转节点做右节点

以下就是模拟TreeMap进行左旋转的代码:
在这里插入图片描述
在这里插入图片描述

5.2 红黑树右旋

在这里插入图片描述
红黑树的右旋其实就是以旋转节点为中心的顺时针顺序旋转,最后效果如上图所示。总结起来就两点:
1、旋转节点左节点成为其父节点
2、左节点的右节点给旋转节点做左节点

以下就是模拟TreeMap进行右旋转的代码:
在这里插入图片描述

六:添加节点
6.1 节点添加

在这里插入图片描述
根节点等于null不就是说没有节点么,这是开张第一位客官,直接实例化节点Entry后将其赋值给root属性即可。compare()方法上面讲过,其实在这里的目的就是判断你是不是既没传Comparator比较器,存储元素又没有实现Comparable接口,真这样就报错的咯

在这里插入图片描述
cpr不等于空就是说你传了比较器,do while操作嘛,反正这个过程你要么找到一样的key取而代之返回,要么你就老老实实找到最后一个叶子结点当爹
在这里插入图片描述
没传比较器的时候compara()方法会有一次强转,长痛不如短痛。key值为null直接给你干一个异常就OK结束即可。如果不是null就还是老规矩,do while循环操作嘛,与传递了Comparator比较器一致有两种情况,看你是哪种骚操作
在这里插入图片描述
走到这里的都是有了爹的孩子,这时候就是看看你比你爹大还是小。以右为大,青出于蓝而胜于蓝的靠右站,其余的靠左凉快。cmp就是前面最后一次跳出循环的时候你和你爹较量的结果

6.2 红黑树调整

在这里插入图片描述
注意最后一个条件,一下所有情况的枚举都是建立在父节点为红色节点的前提下进行的

前面讲了红黑树节点的变更有可能就会破坏掉红黑树的约束,所以需要调用fixAfterInsertion()更改下节点颜色或者是调整下红黑树结构。就六种情况,划分为两类。第一类就是新插入节点的父节点是爷爷节点的右节点,第二种情况就是左节点。反正拗口,下面列举左节点的情况,右节点就是相对的,把左右修改下就OK:
在这里插入图片描述

  • if判断爷爷节点的左节点是不是等于父亲节点,这不就是说父亲节点为爷爷节点的左节点么
  • 叔叔节点是红色
    1 ) 将“父节点”设为黑色
    2 ) 将“叔叔节点”设为黑色
    3 ) 将“爷爷节点”设为“红色”
    4 ) 将“爷爷节点”设为“当前节点”(红色节点)
  • 叔叔节点是黑色,且当前节点是其父节点的右孩子
    1 ) 将“父节点”作为“新的当前节点”
    2 ) 以“新的当前节点”为支点进行左旋
  • 叔叔节点是黑色,且当前节点是其父节点的左孩子
    1 ) 将“父节点”设为“黑色”
    2 ) 将“爷爷节点”设为“红色”
    3 ) 以“爷爷节点”为支点进行右旋

为了代码的完整性,下面粘贴出TreeMap处理右节点的逻辑,自己总结下就行了
在这里插入图片描述

七:NavigableMap

TreeMap继承实现NaviableMap接口,该接口继承自SortedMap。接口提供系列大小比较的API,返回值分为key与节点Entry
在这里插入图片描述
在这里插入图片描述

  • lower: 返回小于给定key的最大key/Entry
  • higher:返回大于给定key的最小key/Entry
  • ceiling:返回等于给定值的key/Entry或大于给定值最小的key/value
  • floor : 返回等于给定值的key/Entry或小于给定值最大的key/value
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值