文章目录
TreeMap 简介
TreeMap是NavigableMap接口(SortedMap的子接口)的实现类,是一个有序的key-value集合,它是通过红黑树(Red-Black tree)实现的。TreeMap能够把它保存的记录根据key键排序,它有两种排序方式:
- 自然排序(默认排序):TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException;
- 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现
Comparable 接口。
注意:
- 判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0;
- TreeMap存储的键key不可为null。
一、红黑树简单回顾
1.1 红黑树规则特点
- 节点分为红色或者黑色;
- 根节点必为黑色;
- 叶子节点都为黑色,且为null;
- 连接红色节点的两个子节点都为黑色(红黑树不会出现相邻的红色节点);
- 从任意节点出发,到其每个叶子节点的路径中包含相同数量的黑色节点;
- 新加入到红黑树的节点为红色节点;
1.2 红黑树自平衡基本操作
- 变色:在不违反上述红黑树规则特点情况下,将红黑树某个node节点颜色由红变黑,或者由黑变红;
- 左旋:逆时针旋转两个节点,让一个节点被其右子节点取代,而该节点成为右子节点的左子节点;左旋时机是父亲是红色,叔叔是黑色,当前是右子树,则直接以父亲为支点进行左旋;
- 右旋:顺时针旋转两个节点,让一个节点被其左子节点取代,而该节点成为左子节点的右子节点;右旋时机::父亲是红色,叔叔是黑色,当前是左子树,则把父亲变成黑色,爷爷变成红色,再以爷爷为支点进行右旋;
二、实现原理
TreeMap底层是基于红黑树实现,具有红黑树的特点;在插入或删除树节点时,通过遍历树,找到对于位置,进行插入或删除。此时红黑树的平衡可能被破坏了。此时我们通过变色、左旋转和右旋转来进行树的平衡,从而使得整个树重新达到平衡并且满足红黑树的所有性质。
三、源码分析
3.1 继承与实现关系
- 继承于AbstractMap【 提供 Map 接口的骨干实现】,实现了NavigableMap,NavigableMap接口继承了SortedMap接口,可支持一系列的导航定位以及导航操作的方法,所以它是一个有序的Map;
- 实现了Cloneable接口,意味着它能被克隆;
- 实现了java.io.Serializable接口,意味着它支持序列化。
3.2 重要成员信息
- comparator:内部的比较器,若为空,则为自然顺序;
- root:红黑树唯一的根节点;
- size:红黑树中节点Entry的数量;
- modCount: 红黑树结构的调整次数
3.3 构造方法
- TreeMap():默认构造函数,按照key的自然顺序排列;
- TreeMap(Comparator<? super K> comparator):传递Comparator具体实现,按照该实现规则进行排序;
- TreeMap(Map<? extends K, ? extends V> m):传递一个map实体构建TreeMap,按照默认规则排序;
- TreeMap(SortedMap<K, ? extends V> m):传递一个map实体构建TreeMap,按照传递的map的排序规则进行排序。
3.4 数据结构
Entry静态内部类实现了Map的内部接口Entry,提供了红黑树存储结构的java实现,通过left属性可以建立左子树,通过right属性可以建立右子树,通过parent可以往上找到父节点。
3.5 重要方法
3.5.1 存储 put(K key, V value)
对于排序二叉树的创建,其添加节点的过程如下:
- 以根节点为初始节点进行检索。
- 与当前节点进行比对,若新增节点值较大,则以当前节点的右子节点作为新的当前节点。否则以当前节点的左子节点作为新的当前节点。
- 循环递归2步骤知道检索出合适的叶子节点为止。
- 将新增节点与3步骤中找到的节点进行比对,如果新增节点较大,则添加为右子节点;否则添加为左子节点。
put方法源码中通过 fixAfterInsertion(e) 方法来进行自平衡处理,我们回顾一下插入时自平衡调整的逻辑
左旋:
右旋:
3.5.2 读取 get(Object key)
3.5.3 移除 remove(Object key)
删除节点(P)的所有情况:
- p 是跟节点:直接删除P即可;
- P 无子节点:直接删除P节点,若P是红色,则不会影响树的结构,若P是黑色,则进行平衡调整;
- P 有一个子节点:则使用其子节点来替代P,并删除P,若P是黑色,则进行平衡调整;
- P 有两个子节点:需要找一个一个替代节点(规则:右分支最左边,或者左分支最右边的节点),使用替代节点来替代P,并删除P,若P是黑色,则进行平衡调整;
- 4.1 P的兄弟节点Q为红色:进行”改变W. P的颜色,然后进行一次左旋转“处理,处理后转变为下面2、3、4三种情况;
- 4.2 P的兄弟Q是黑色的,且w的俩个孩子都是黑色的:进行”将Q置为红色“处理,,处理后转变为下面3、4两种情况;
- 4.3 P的兄弟Q是黑色的,w的左孩子是红色,w的右孩子是黑色:进行”将兄弟节点与其左子树进行颜色互换然后进行右转“处理,处理后转变为下面4这种情况;
- 4.4 P的兄弟Q是黑色的,且w的右孩子时红色的:进行”交换兄弟节点和父节点的颜色,同时将兄弟节点右子树设置为黑色,最后左旋转“处理。