TreeMap

想了解的 TreeMap 应该是编程领域(尤其是 Java)中的 TreeMap 集合类,本文从核心概念、特性、使用方法到底层原理,做一个通俗易懂的详细介绍,彻底理解它的用法和适用场景。

一、TreeMap 核心定义

TreeMap 是 Java 集合框架中 Map 接口的一个实现类,属于 java.util 包,它的核心特点是:基于红黑树(一种自平衡的二叉查找树)实现,能够对键(Key)进行自动排序。
简单来说,你可以把它理解成一个 “有序的字典”—— 普通的 HashMap 是无序的,而 TreeMap 会按照键的规则自动把键值对排好序,不用你手动处理排序逻辑。

二、TreeMap 核心特性

  1. 有序性
    • 默认按键的自然顺序排序(比如 Integer 按数字大小、String 按字典序);
    • 也可以通过构造方法传入 Comparator 自定义排序规则(比如按字符串长度、按数字倒序)。
     
  2. 底层结构
    • 基于红黑树实现,红黑树是一种平衡二叉查找树,保证了增删改查的时间复杂度都是 O(log n)(比 HashMap 的 O(1) 慢,但胜在有序)。
     
  3. 不允许键为 null
    • 因为排序需要比较键的大小,null 无法参与比较,所以键为 null 会抛出 NullPointerException;值可以为 null。
     
  4. 非线程安全
    • 多线程环境下使用需要手动同步(比如用 Collections.synchronizedSortedMap() 包装),或使用 ConcurrentSkipListMap(并发版的有序 Map)。
     
  5. 元素唯一性
    • 键的唯一性由 equals()compareTo()/Comparator 共同保证(红黑树通过比较判断键是否重复)。

三、TreeMap 常用方法与示例

下面通过完整代码示例,展示 TreeMap 的核心用法:

1. 基础使用(自然排序)

java
import java.util.TreeMap;

public class TreeMapBasic {
    public static void main(String[] args) {
        // 1. 创建 TreeMap,默认按键的自然顺序排序(Integer 升序)
        TreeMap<Integer, String> treeMap = new TreeMap<>();

        // 2. 添加键值对
        treeMap.put(3, "张三");
        treeMap.put(1, "李四");
        treeMap.put(2, "王五");
        treeMap.put(4, "赵六");

        // 3. 遍历(输出会按键升序排列:1->2->3->4)
        System.out.println("默认自然排序结果:");
        for (Integer key : treeMap.keySet()) {
            System.out.println(key + " : " + treeMap.get(key));
        }

        // 4. 常用方法
        System.out.println("\n键的最小值:" + treeMap.firstKey()); // 输出 1
        System.out.println("键的最大值:" + treeMap.lastKey());   // 输出 4
        System.out.println("小于等于 3 的最大键:" + treeMap.floorKey(3)); // 输出 3
        System.out.println("大于 2 的最小键:" + treeMap.ceilingKey(2)); // 输出 2
        System.out.println("移除并返回最小键的键值对:" + treeMap.pollFirstEntry()); // 输出 1=李四
    }
}
 
输出结果:
 
plaintext
默认自然排序结果:
1 : 李四
2 : 王五
3 : 张三
4 : 赵六

键的最小值:1
键的最大值:4
小于等于 3 的最大键:3
大于 2 的最小键:2
移除并返回最小键的键值对:1=李四

2. 自定义排序(Comparator)

 
如果想按键的倒序排列,或按自定义规则排序,可传入 Comparator
 
java
import java.util.Comparator;
import java.util.TreeMap;

public class TreeMapCustomSort {
    public static void main(String[] args) {
        // 1. 传入 Comparator,按 Integer 键倒序排序
        TreeMap<Integer, String> treeMap = new TreeMap<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // 倒序:o2 - o1(升序是 o1 - o2)
                return o2 - o1;
            }
        });

        treeMap.put(3, "张三");
        treeMap.put(1, "李四");
        treeMap.put(2, "王五");

        // 遍历(输出按键倒序:3->2->1)
        System.out.println("自定义倒序排序结果:");
        treeMap.forEach((key, value) -> System.out.println(key + " : " + value));
    }
}
 
 
输出结果:
plaintext
自定义倒序排序结果:
3 : 张三
2 : 王五
1 : 李四

3. 自定义对象作为键(需实现 Comparable)

如果用自定义对象(比如 User)作为键,必须让对象实现 Comparable 接口(或传入 Comparator),否则会抛出 ClassCastException
 
java
import java.util.TreeMap;

// 自定义 User 类,实现 Comparable 接口(按 age 升序)
class User implements Comparable<User> {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 实现 compareTo 方法,定义排序规则
    @Override
    public int compareTo(User o) {
        // 按年龄升序,若年龄相同按姓名字典序
        if (this.age != o.age) {
            return this.age - o.age;
        }
        return this.name.compareTo(o.name);
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

public class TreeMapCustomKey {
    public static void main(String[] args) {
        TreeMap<User, String> treeMap = new TreeMap<>();
        treeMap.put(new User("张三", 25), "北京");
        treeMap.put(new User("李四", 22), "上海");
        treeMap.put(new User("王五", 25), "广州");

        // 遍历(按 age 升序,age 相同按 name 排序)
        System.out.println("自定义对象键的排序结果:");
        treeMap.forEach((key, value) -> System.out.println(key + " : " + value));
    }
}
 
输出结果:
plaintext
自定义对象键的排序结果:
User{name='李四', age=22} : 上海
User{name='张三', age=25} : 北京
User{name='王五', age=25} : 广州

四、TreeMap 适用场景

  • 需要有序遍历键值对的场景(比如按时间、数字、字母顺序展示数据);
  • 需要快速查找 “最大 / 最小键”“小于 / 大于某个键的最近值” 的场景(比如排行榜、区间查询);
  • 不要求极致的增删改查性能,但要求有序的场景(如果追求高性能且无需有序,优先用 HashMap)。

五、TreeMap vs HashMap 核心对比

 
特性TreeMapHashMap
底层结构 红黑树 数组 + 链表 / 红黑树
有序性 按键有序(自然 / 自定义) 无序(JDK8 后按插入顺序)
时间复杂度 增删改查 O (log n) 增删改查 O (1)(平均)
键是否可为 null 不可 可以(仅一个)
排序支持 天然支持 需手动排序(如 Collections.sort)
 

总结

  1. 核心定位:TreeMap 是有序的 Map 实现,基于红黑树,能自动对键排序,适用于需要有序遍历或区间查询的场景;
  2. 关键规则:键必须可比较(实现 Comparable 或传入 Comparator),不允许 null 键,非线程安全;
  3. 选型建议:无需有序选 HashMap(性能更高),需要有序选 TreeMap,并发场景选 ConcurrentSkipListMap。
posted @ 2026-01-23 09:52  野鹤闲人  阅读(2)  评论(0)    收藏  举报