首页 > 其他分享 >TreeMap

TreeMap

时间:2024-07-13 23:34:32浏览次数:13  
标签:return parent Comparator TreeMap key null

  • TreeMap 由红黑树实现,可以保持元素的自然顺序,或者实现了 Comparator 接口的自定义顺序
  • 红黑树(英语:Red–black tree)是一种自平衡的二叉查找树(Binary Search Tree),结构复杂,但却有着良好的性能,完成查找、插入和删除的时间复杂度均为 log(n)。

自然顺序

  • 默认情况下,TreeMap 是根据 key 的自然顺序排列的。
// 红黑树中包含的元素数
private transient int size = 0;

// 比较器,为null时表示自然顺序
private final Comparator<? super K> comparator;

public V put(K key, V value) {
    // 将根节点赋值给变量t
    Entry<K, V> t = root;
    // 如果根节点为null,说明TreeMap为空
    if (t == null) {
        // 检查key的类型是否合法
        compare(key, key); // type (and possibly null) check
        // 创建一个新节点作为根节点
        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        // 返回null,表示插入成功
        return null;
    }
    int cmp;
    Entry<K, V> parent;
    // split comparator and comparable paths
    // 获取比较器,根据使用的比较方法进行查找
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        // 如果使用了Comparator
        do {
            // 将当前节点赋值给parent
            parent = t;
            // 使用Comparator比较key和t的键的大小
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                // 在t的左子树中查找
                t = t.left;
            else if (cmp > 0)
                // 在t的右子树中查找
                t = t.right;
            else
                // 直接更新t的值,覆盖原来的值
                return t.setValue(value);
        } while (t != null);
    } else {
        // 如果没有使用Comparator
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
        // 将key强制转换为Comparable类型
        Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    // 如果没有找到相同的键,需要创建一个新节点插入到TreeMap中
    Entry<K, V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        // 将e作为parent的左子节点
        parent.left = e;
    else
        // 将e作为parent的右子节点
        parent.right = e;
    // 插入节点后需要进行平衡操作
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}
  • String类的compareTo()
public int compareTo(String anotherString) {
    // 获取当前字符串和另一个字符串的长度
    int len1 = value.length;
    int len2 = anotherString.value.length;
    // 取两个字符串长度的较短者作为比较的上限
    int lim = Math.min(len1, len2);
    // 获取当前字符串和另一个字符串的字符数组
    char v1[] = value;
    char v2[] = anotherString.value;

    int k = 0;
    // 对两个字符串的每个字符进行比较
    while (k < lim) {
        char c1 = v1[k];
        char c2 = v2[k];
        // 如果两个字符不相等,返回它们的差值
        if (c1 != c2) {
            return c1 - c2;
        }
        k++;
    }
    // 如果两个字符串前面的字符都相等,返回它们长度的差值
    return len1 - len2;
}

自定义顺序

  • TreeMap 提供了可以指定排序规则的构造方法
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}
  • Comparator.reverseOrder() 返回的是 Collections.ReverseComparator 对象,就是用来反转顺序的
TreeMap<Integer, String> map = new TreeMap<>(Comparator.reverseOrder());
private static class ReverseComparator
    implements Comparator<Comparable<Object>>, Serializable {
    private static final long serialVersionUID = 7207038068494060240L;
    
    // 单例模式,用于表示逆序比较器
    static final ReverseComparator REVERSE_ORDER
        = new ReverseComparator();
	// 实现比较方法,对两个实现了Comparable接口的对象进行逆序比较
    public int compare(Comparable<Object> c1, Comparable<Object> c2) {
        // 调用c2的compareTo()方法,以c1为参数,实现逆序比较
        return c2.compareTo(c1);
    }

    // 反序列化时,返回Collections.reverseOrder(),保证单例模式
    private Object readResolve() { return Collections.reverseOrder(); }

    // 返回正序比较器
    @Override
    public Comparator<Comparable<Object>> reversed() {
        return Comparator.naturalOrder();
    }
}

排序的用处

// 获取最后一个key
Integer highestKey = map.lastKey();
// 获取第一个key
Integer lowestKey = map.firstKey();

// 获取key之前的keySet
Set<Integer> keysLessThan3 = map.headMap(3).keySet();
// 获取key之后的keySet
Set<Integer> keysGreaterThanEqTo3 = map.tailMap(3).keySet();

Map<Integer, String> headMap = map.headMap(3);
Map<Integer, String> tailMap = map.tailMap(4);
// 获取key在大于等于2,且小于4的键值对
Map<Integer, String> subMap = map.subMap(2, 4);

Map的选择

特性 TreeMap HashMap LinkedHashMap
排序 支持 不支持 不支持
插入顺序 不保证 不保证 保证
查找效率 O(log n) O(1) O(1)
空间占用 通常较大 通常较小 通常较大
适用场景 需要排序的场景 无需排序的场景 需要保持插入顺序

标签:return,parent,Comparator,TreeMap,key,null
From: https://www.cnblogs.com/sprinining/p/18300969

相关文章

  • 13-TreeSet和TreeMap基本介绍
    13-TreeSet和TreeMap基本介绍介绍汇总:TreeSet基本介绍TreeMap基本介绍1-TreeSet基本介绍TreeSet类用于存储一组对象,并将对象按照自然规则(实现Comparator接口的)或者指定Comparator对象的比较器进行排序。TreeSet类中的底层是TreeMap。key值不可以为null,也不......
  • 在Java中,Map 接口的实现(如 HashMap,LinkedHashMap,TreeMap 等)并不保证遍历 keySet() 或
    在Java中,Map接口的实现(如HashMap,LinkedHashMap,TreeMap等)并不保证遍历keySet()或entrySet()时的顺序。但是,某些特定的Map实现确实提供了特定的遍历顺序。1、HashMap:它基于哈希表实现,并不保证映射的顺序,特别是遍历顺序。因此,当你使用map.keySet()遍历HashMap时,结果可......
  • 双列集合 HashMap以及TreeMap底层原理
    双列集合 特点:    双列集合一次需要存一对数据,分别为键和值    键不能重复,值可以重复    键和值是一一对应的,每个键只能找到自己对应的值        键和值这个整体在Java中叫做“Entry对象”Map的常见API    Map是双列集合的顶......
  • 58.容器_TreeMap容器的使用
    TreeMap容器的使用TreeMap和HashMap同样实现了Map接口,所以,对于API的用法来说是没有区别的。HashMap效率高于TreeMap;TreeMap是可以对键进行排序的一种容器,在需要对键排序时可选用TreeMap。TreeMap底层是基于红黑树实现的。在使用TreeMap时需要给定排序规则:元素自身实现比较规......
  • 我什么时候应该使用TreeMap 而不是 PriorityQueue?反之亦然?
    引子之前周赛(第390场周赛记录-快手)时遇到一题(题干描述见下图,实现代码见周赛记录),需要保持容器元素的动态有序(即随着插入删除操作后列表始终是有序的)。尝试过很多数据结构或方案,如列表存储然后手动调用Arrays.sort()进行排序、使用优先队列实现大/小根堆的方式,但无一例外全部超时......
  • TreeMap从添加第二个元素开始,需要进行排序,原始类继承Comparable<Student>接口实现comp
    重写compareTo方法,关于o的理解@OverridepublicintcompareTo(Studento){//关于o,是红黑树中从第二个开始进入的元素,需//要和已存在的元素比较,该o是在第二个add//调用时,传入这里的Student对象。//根据题设,先用年龄排序in......
  • 集合系列(五) -TreeMap详解
    一、摘要在集合系列的第一章,咱们了解到,Map的实现类有HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties等等。本文主要从数据结构和算法层面,探讨TreeMap的实现。二、简介JavaTreeMap实现了SortedMap接口,也就是说会按照key的大......
  • SortedMap、NavigableMap、TreeMap介绍和使用
    SortedMap、NavigableMap、TreeMap介绍和使用SortedMap接口:SortedMap是一个接口,继承自Map接口,它定义了对键值对按照键的自然顺序或自定义顺序进行排序的功能。SortedMap中的键值对是按照键的顺序排列的,因此可以根据键的顺序进行范围查找和遍历操作。SortedMap接口提供了一......
  • TreeMap练习
    TreeMap练习1."aababcabcdabcde",获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)packagecom.shujia.day14;importjava.util.Map;importjava.util.Set;importjava.util.TreeMap;publicclassTreeMapTest1{publicstaticvoidmain(String[]arg......
  • TreeMap排序
    实现TreeMap后默认为key升序排序,如果要实现key其他排序规则,可以使用Comparator对象作为参数,前提是key为可以排序的类型(String,int等类型)1Map<String,People>map=newTreeMap<>(newComparator<String>(){2@Override3publicintcompare(finalStringo1,final......