TreeMap


TreeMap 是 SortedMap 的子类,所以它具有排序功能。它是基于红黑树数据结构实现的,每一个键值对<key, value>都是一个结点,默认情况下按照key自然排序,另一种是可以通过传入定制的Comparator进行自定义规则排序。TreeMap是非线程安全的。
在这里插入图片描述


整体架构

TreeMap 底层的数据结构就是红黑树,和 HashMap 的红黑树结构一样。不同的是,TreeMap 利用了红黑树左节点小,右节点大的性质,根据 key 进行排序,使每个元素能够插入到红黑树大小适当的位置,维护了 key 的大小关系,适用于 key 需要排序的场景。因为底层使用的是平衡红黑树的结构,所以 containsKey、get、put、remove 等方法的时间复杂度都是 log(n)。
在这里插入图片描述
TreeMap常见属性

//比较器,如果外部有传进来 Comparator 比较器,首先用外部的
//如果外部比较器为空,则使用 key 自己实现的 Comparable#compareTo 方法
//比较手段和上面日常工作中的比较 demo 是一致的
private final Comparator<? super K> comparator;

//红黑树的根节点
private transient Entry<K,V> root;

//红黑树的已有元素大小
private transient int size = 0;

//树结构变化的版本号,用于迭代过程中的快速失败场景
private transient int modCount = 0;

//红黑树的节点
static final class Entry<K,V> implements Map.Entry<K,V> {}

TreeMap的主要操作

// 初始化方法1(未传入定制的comparator,默认是自然排序)
TreeMap<Integer, Object> treeMap = new TreeMap<>();
treeMap.put(2, "Two");
treeMap.put(1, "One");
System.out.println(treeMap);

//初始化方法2(传入了定制的comparator,按照key值降序)
TreeMap<Integer, Object> treeMap1 = new TreeMap<>((o1, o2) -> Integer.compare(o2, o1));
treeMap1.put(1, "One");
treeMap1.put(2, "Two");
treeMap1.put(3, "Three");
treeMap1.put(4, "Four");
System.out.println(treeMap1);
for (int i : treeMap1.keySet()) {
    System.out.println(treeMap1.get(i));
}

// 初始化方法3(传入没有定制comparator的map作为参数)
TreeMap<Integer, Object> treeMap2 = new TreeMap<>(treeMap);
for (int i : treeMap2.keySet()) {
    System.out.println(treeMap2.get(i));
}

// 初始化方法4(传入有定制comparator的map作为参数)
TreeMap<Integer, Object> treeMap3 = new TreeMap<>(treeMap1);
treeMap3.put(10, "Ten");
treeMap3.put(9, "Nine");
for(int i : treeMap3.keySet()) {
    System.out.println(treeMap3.get(i));
}

新增节点

1:判断红黑树的节点是否为空,为空的话,新增的节点直接作为根节点,代码如下:

Entry<K,V> t = root;
//红黑树根节点为空,直接新建
if (t == null) {
    // compare 方法限制了 key 不能为 null
    compare(key, key); // type (and possibly null) check
    // 成为根节点
    root = new Entry<>(key, value, null);
    size = 1;
    modCount++;
    return null;
}

2:根据红黑树左小右大的特性,进行判断,找到应该新增节点的父节点,代码如下:

Comparator<? super K> cpr = comparator;
if (cpr != null) {
    //自旋找到 key 应该新增的位置,就是应该挂载那个节点的头上
    do {
        //一次循环结束时,parent 就是上次比过的对象
        parent = t;
        // 通过 compare 来比较 key 的大小
        cmp = cpr.compare(key, t.key);
        //key 小于 t,把 t 左边的值赋予 t,因为红黑树左边的值比较小,循环再比
        if (cmp < 0)
            t = t.left;
        //key 大于 t,把 t 右边的值赋予 t,因为红黑树右边的值比较大,循环再比
        else if (cmp > 0)
            t = t.right;
        //如果相等的话,直接覆盖原值
        else
            return t.setValue(value);
        // t 为空,说明已经到叶子节点了
    } while (t != null);
}

3:在父节点的左边或右边插入新增节点,代码如下:

//cmp 代表最后一次对比的大小,小于 0 ,代表 e 在上一节点的左边
if (cmp < 0)
    parent.left = e;
//cmp 代表最后一次对比的大小,大于 0 ,代表 e 在上一节点的右边,相等的情况第二步已经处理了。
else
    parent.right = e;

4:着色旋转,达到平衡,结束。

TreeMap 是禁止 key 是 null 值的。TreeMap 相对来说比较简单,红黑树和 HashMap 比较类似,比较关键的是通过 compare 来比较 key 的大小,然后利用红黑树左小右大的特性,为每个 key 找到自己的位置,从而维护了 key 的大小排序顺序。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lw中

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值