导读:本期聚焦于小伙伴创作的《Java中的TreeMap有什么特点?如何实现按键排序并适配NavigableMap接口?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中的TreeMap有什么特点?如何实现按键排序并适配NavigableMap接口?》有用,将其分享出去将是对创作者最好的鼓励。

Java中的TreeMap是集合框架里的重要成员,它基于红黑树数据结构实现,和HashMap的无序存储不同,TreeMap的所有键值对都会按照键的顺序进行排列,同时它实现了NavigableMap接口,提供了很多便于范围操作的方法,在很多需要有序映射的场景下都有广泛应用。

Java中的TreeMap有什么特点?如何实现按键排序并适配NavigableMap接口?

TreeMap的核心特点

1. 有序性

TreeMap的最核心特点就是有序,排序规则有两种配置方式:一是使用键对象的自然顺序,要求键类实现Comparable接口;二是创建TreeMap时传入自定义的Comparator比较器,按照自定义规则排序。如果两种方式都没有配置,且键没有实现Comparable接口,运行时会抛出ClassCastException

2. 基于红黑树实现

TreeMap的底层是红黑树,这是一种自平衡的二叉查找树,插入、删除、查找操作的时间复杂度都是O(log n),相比HashMap的O(1)平均复杂度要低,但胜在有序性带来的操作优势。红黑树的特性保证了树的高度不会过高,避免了二叉查找树退化成链表的情况。

3. 非线程安全

TreeMap和HashMap一样,不是线程安全的,如果需要在多线程环境下使用,需要通过Collections.synchronizedSortedMap方法包装,或者考虑使用ConcurrentSkipListMap替代。

4. 不允许null键(自定义比较器允许的情况除外)

如果使用自然排序或者比较器不支持null值比较,往TreeMap中插入null键会抛出NullPointerException。如果使用自定义比较器且比较器可以处理null值,那么可以插入null键。

按键排序的实现方式

要实现TreeMap的按键排序,只需要正确配置排序规则即可,以下是两种常见场景的示例:

自然顺序排序

当键类实现了Comparable接口时,TreeMap默认使用自然顺序排序,比如String、Integer等包装类都已经实现了该接口。

import java.util.TreeMap;

public class TreeMapNaturalSort {
    public static void main(String[] args) {
        // 键为String类型,使用自然字典序排序
        TreeMap<String, Integer> map = new TreeMap<>();
        map.put("apple", 3);
        map.put("banana", 1);
        map.put("cherry", 2);
        // 遍历输出会按照键的升序排列
        for (String key : map.keySet()) {
            System.out.println(key + " : " + map.get(key));
        }
    }
}

自定义比较器排序

如果需要按照自定义规则排序,比如按照字符串长度排序,可以在构造TreeMap时传入Comparator

import java.util.Comparator;
import java.util.TreeMap;

public class TreeMapCustomSort {
    public static void main(String[] args) {
        // 自定义比较器:按照键的字符串长度升序排序,长度相同按照字典序排序
        TreeMap<String, Integer> map = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                if (o1.length() != o2.length()) {
                    return o1.length() - o2.length();
                }
                return o1.compareTo(o2);
            }
        });
        map.put("a", 1);
        map.put("bb", 2);
        map.put("ccc", 3);
        map.put("ab", 4);
        // 遍历输出顺序为a, ab, bb, ccc
        for (String key : map.keySet()) {
            System.out.println(key + " : " + map.get(key));
        }
    }
}

模拟按键排序的字典树功能

字典树(Trie)的核心特点是按照前缀匹配查询,我们可以利用TreeMap的有序性来模拟简单的字典树前缀查询功能,因为TreeMap的键是有序的,所有相同前缀的键会连续排列在映射中。

以下是使用TreeMap实现前缀查询的示例:

import java.util.NavigableMap;
import java.util.TreeMap;

public class TreeMapTrieDemo {
    public static void main(String[] args) {
        TreeMap<String, String> trieMap = new TreeMap<>();
        // 插入一些单词作为字典树节点
        trieMap.put("app", "应用");
        trieMap.put("apple", "苹果");
        trieMap.put("application", "应用程序");
        trieMap.put("banana", "香蕉");
        trieMap.put("band", "乐队");

        String prefix = "app";
        // 获取所有以prefix为前缀的键:从prefix开始,到prefix+最后一个字符的范围
        NavigableMap<String, String> subMap = trieMap.subMap(prefix, true, prefix + Character.MAX_VALUE, false);
        System.out.println("前缀为" + prefix + "的单词:");
        for (String key : subMap.keySet()) {
            System.out.println(key + " : " + subMap.get(key));
        }
    }
}

上述代码中,subMap方法获取了键在[prefix, prefix + Character.MAX_VALUE)范围内的所有键值对,因为TreeMap有序,所以这个范围刚好是所有以prefix为前缀的键,实现了类似字典树的前缀查询效果。

NavigableMap接口的常用方法

TreeMap实现了NavigableMap接口,该接口提供了一系列导航相关的方法,方便进行范围查询、极值获取、逆序遍历等操作,以下是常用方法的说明和示例:

方法名作用说明
lowerKey(key)返回严格小于给定key的最大键,不存在则返回null
floorKey(key)返回小于等于给定key的最大键,不存在则返回null
ceilingKey(key)返回大于等于给定key的最小键,不存在则返回null
higherKey(key)返回严格大于给定key的最小键,不存在则返回null
firstKey()返回当前映射中的第一个(最小的)键
lastKey()返回当前映射中的最后一个(最大的)键
subMap(fromKey, fromInclusive, toKey, toInclusive)返回键范围在[fromKey, toKey]内的子映射,inclusive参数控制是否包含边界
descendingMap()返回当前映射的逆序视图

以下是这些方法的实际使用示例:

import java.util.TreeMap;
import java.util.NavigableMap;

public class NavigableMapDemo {
    public static void main(String[] args) {
        TreeMap<Integer, String> map = new TreeMap<>();
        map.put(1, "一");
        map.put(3, "三");
        map.put(5, "五");
        map.put(7, "七");
        map.put(9, "九");

        System.out.println("小于5的最大键:" + map.lowerKey(5)); // 输出3
        System.out.println("小于等于5的最大键:" + map.floorKey(5)); // 输出5
        System.out.println("大于等于5的最小键:" + map.ceilingKey(5)); // 输出5
        System.out.println("大于5的最小键:" + map.higherKey(5)); // 输出7
        System.out.println("第一个键:" + map.firstKey()); // 输出1
        System.out.println("最后一个键:" + map.lastKey()); // 输出9

        // 获取键在[3,7]范围内的子映射,包含3和7
        NavigableMap<Integer, String> subMap = map.subMap(3, true, 7, true);
        System.out.println("子映射的键集:" + subMap.keySet()); // 输出[3,5,7]

        // 逆序遍历
        System.out.println("逆序键集:" + map.descendingKeySet()); // 输出[9,7,5,3,1]
    }
}

使用注意事项

  • 如果键的类型没有实现Comparable接口,且构造TreeMap时没有传入自定义比较器,运行时会抛出类型转换异常。
  • 自定义比较器需要保证比较逻辑的一致性,即如果compare(a,b)==0,那么a.equals(b)最好也为true,否则TreeMap的行为会和Map接口的通用约定不一致。
  • TreeMap的迭代顺序是键的排序顺序,如果需要按照插入顺序排序,应该使用LinkedHashMap
  • NavigableMap返回的视图(比如子映射、逆序映射)都是原映射的实时视图,修改视图会影响原映射,修改原映射也会影响视图。

TreeMapNavigableMap按键排序字典树修改时间:2026-06-09 05:15:38

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。