> 文章列表 > TreeMap 详解

TreeMap 详解

TreeMap 详解

概述

TreeMap 是 Java 中的一种集合类,它实现了 SortedMap 接口,可以根据键的自然顺序或者自定义顺序对元素进行排序,底层实现采用了红黑树(Red-Black Tree)的数据结构。TreeMap 中的元素是按照键的排序顺序存储的,可以高效地进行查找、插入和删除操作。

基本特点

  1. 有序性:TreeMap 通过红黑树数据结构来维护键值对的顺序,因此它能够保证键值对按照键的自然顺序或自定义顺序排列,而且可以快速地进行插入、查找和删除等操作。

  2. 元素唯一:TreeMap 中的键是唯一的,因此相同的键只能存储一个元素。如果在 TreeMap 中插入一个已经存在的键,则新的值会覆盖原有的值

  3. 可排序性:由于 TreeMap 是有序的,因此它提供了多种按照键排序的方法,比如自然排序和自定义排序。

  4. 映射性:TreeMap 是一种映射表数据结构,可以用键来查找对应的值,同时也支持键值对的遍历操作。

  5. 线程不安全:与 HashMap 类似,TreeMap 也是线程不安全的,如果在多线程环境下使用,需要进行同步处理。

  6. 性能优异:TreeMap 的基本操作的时间复杂度为 O(log n),因此它具有较好的性能表现,适合处理大量的键值对。

  7. 内存占用较高:由于 TreeMap 内部采用红黑树数据结构,因此它的内存占用较高,比 HashMap 稍微大一些。

需要注意的是,如果在 TreeMap 中存储 null 键或值,会抛出 NullPointerException 异常。如果需要在 TreeMap 中存储 null 键或值,可以使用自定义排序,并在 compare 方法中处理 null 值的情况。

因为在使用自然排序(Natural Ordering)时,如果在 TreeMap 中插入 null 键,会抛出 NullPointerException 异常。这是因为在自然排序下,TreeMap 会使用键的 compareTo 方法进行比较,而如果键为 null,则无法进行比较,从而导致异常的抛出。

但是,在使用自定义排序(Custom Ordering)时,可以使用 null 作为键。自定义排序是通过实现 Comparator 接口来定义的,其中 compare 方法用于比较两个对象。在自定义排序下,如果 compare 方法返回 0,表示两个对象相等,因此可以使用 null 作为键。例如:

// 自定义排序,允许 null 键
TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() {@Overridepublic int compare(String s1, String s2) {if (s1 == null && s2 == null) {return 0;}if (s1 == null) {return -1;}if (s2 == null) {return 1;}return s1.compareTo(s2);}
});// 存储 null 键和值
treeMap.put(null, "value1");
treeMap.put("key2", null);// 获取值
String value1 = treeMap.get(null); // value1
String value2 = treeMap.get("key2"); // null

需要注意的是,虽然自定义排序允许使用 null 作为键,但在实际开发中,尽量避免使用 null 值,因为它容易引起空指针异常等问题,不利于程序的可读性和可维护性。 

TreeMap 的创建和基本操作

  1. 创建 TreeMap 对象

    TreeMap<Key, Value> treeMap = new TreeMap<>();
    
  2.  添加元素
    treeMap.put(key, value);
    
  3. 删除元素

    treeMap.remove(key);
    
  4. 获取元素

    treeMap.get(key);
    

TreeMap的排序和遍历

  1. 自然排序

    在 Java 中,TreeMap 的自然排序指的是按照键的自然顺序进行排序。对于字符串类型的键,自然顺序是按照字典序排序;对于数字类型的键,自然顺序是按照数字大小排序。

    如果要使用 TreeMap 的自然排序,只需要使用无参构造函数创建 TreeMap 对象即可。例如,下面的代码创建了一个按照自然顺序排序的 TreeMap 对象,并向其中插入了一些元素:

    import java.util.TreeMap;public class Main {public static void main(String[] args) {// 创建一个按照自然顺序排序的 TreeMap 对象TreeMap<String, Integer> treeMap = new TreeMap<>();// 插入元素treeMap.put("ccc", 1);treeMap.put("aaa", 2);treeMap.put("ddd", 3);treeMap.put("bbb", 4);// 遍历 TreeMapfor (String key : treeMap.keySet()) {System.out.println(key + ": " + treeMap.get(key));}}
    }
    

    输出结果为:

    aaa: 2
    bbb: 4
    ccc: 1
    ddd: 3

  2. 自定义排序

    除了使用默认的排序方式,也可以使用自定义的排序方式来对 TreeMap 中的键进行排序。这可以通过在创建 TreeMap 对象时,传入一个比较器(Comparator)对象来实现。比较器是一个接口,需要实现其中的 compare 方法,该方法用于定义键的排序规则。

    例如,我们可以创建一个按照键的长度降序排序的 TreeMap 对象:

    import java.util.Comparator;
    import java.util.TreeMap;public class Main {public static void main(String[] args) {// 创建一个按照键的长度降序排序的 TreeMap 对象TreeMap<String, Integer> treeMap = new TreeMap<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return Integer.compare(o2.length(), o1.length());}});// 插入元素treeMap.put("abc", 1);treeMap.put("a", 2);treeMap.put("defg", 3);treeMap.put("bcd", 4); //长度和"abc" 一样,不输出// 遍历 TreeMapfor (String key : treeMap.keySet()) {System.out.println(key + ": " + treeMap.get(key));}}
    }
    

    输出结果为:

    defg: 3
    abc: 1
    a: 2

  3. 遍历 TreeMap:可以使用迭代器(Iterator)或者 for-each 循环遍历 TreeMap 中的键值对。
        // 遍历 TreeMapfor (String key : treeMap.keySet()) {System.out.println(key + ": " + treeMap.get(key));}// 使用迭代器遍历 TreeMapIterator<Map.Entry<String, Integer>> iterator = treeMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, Integer> entry = iterator.next();System.out.println(entry.getKey() + ": " + entry.getValue());}
    

 TreeMap 的其他特性

  1. 获取第一个和最后一个键
    Key firstKey = treeMap.firstKey();
    Key lastKey = treeMap.lastKey();
    
  2. 获取小于或等于某个键的最大键
    Key floorKey = treeMap.floorKey(key);
    
  3. 获取大于或等于某个键的最小键
    Key ceilingKey = treeMap.ceilingKey(key);
    

 本质上红黑树实现的,所以以此重点掌握红黑树即可