TreeMap 是 Java 中的一种集合类,它实现了 SortedMap 接口,提供了基于红黑树的有序映射。与普通的 HashMap 不同,TreeMap 中的键值对是按照键的顺序进行排序的。
一、TreeMap 特点
- 有序性:TreeMap 中的元素按照键的顺序进行排序,并且可以根据键进行范围查找。
- 基于红黑树:TreeMap 底层使用红黑树(自平衡二叉查找树)来组织键值对。红黑树保持了键的有序性,并保证了插入、删除和查找操作的较好性能(近似 O(log n))。
- 自然顺序与自定义顺序:TreeMap 可以根据键的自然顺序或者通过自定义的比较器进行排序。如果键实现了 Comparable 接口,那么将使用键的自然顺序;否则,需要在构造 TreeMap 对象时传入一个比较器来指定排序规则。
- 高效的操作:TreeMap 提供了一系列方法用于插入、删除、查询和遍历键值对。这些操作的时间复杂度大致为 O(log n),相比于无序集合,TreeMap 在有序性的基础上提供了更高效的操作。
import java.util.Map;
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
// 创建一个 TreeMap
TreeMap<String, Integer> treeMap = new TreeMap<>();
// 添加元素
treeMap.put("apple", 1);
treeMap.put("banana", 2);
treeMap.put("orange", 3);
// 遍历元素(按照键的顺序)
for (Map.Entry<String, Integer> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 范围查询
Map<String, Integer> subMap = treeMap.subMap("apple", "orange");
System.out.println("Submap: " + subMap);
}
}
二、排序规则
TreeMap 默认的排序规则是按照键的自然顺序进行排序。如果键是基本数据类型(如整数、浮点数等)或实现了 Comparable 接口的对象,则会使用其自然顺序进行排序。如果键是自定义类的对象,并且该类没有实现 Comparable 接口,那么在创建 TreeMap 时需要传入一个自定义的比较器(Comparator)来指定排序规则。
当使用自定义比较器时,TreeMap 会根据比较器的规则来确定键的顺序。自定义比较器实现了 Comparator 接口,其中定义了一个 compare 方法,用于比较两个键的大小关系。如果 compare 方法返回负值,则表示第一个键小于第二个键;如果返回正值,则表示第一个键大于第二个键;如果返回零,则表示两个键相等。
1、对于基本数据类型,例如 Integer、Double,它们已经实现了 Comparable 接口,因此它们的自然顺序是根据数值的大小。
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getters and setters
@Override
public int compareTo(Person other) {
// 按照年龄进行比较
return Integer.compare(this.age, other.age);
}
}
TreeMap<Person, String> treeMap = new TreeMap<>();
treeMap.put(new Person("Alice", 25), "Data A");
treeMap.put(new Person("Bob", 30), "Data B");
treeMap.put(new Person("Charlie", 20), "Data C");
// 遍历输出
for (Map.Entry<Person, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey().getName() + ": " + entry.getValue());
}
// 输出结果:
// Charlie: Data C
// Alice: Data A
// Bob: Data B
在上述示例中,Person 对象按照年龄从小到大的顺序进行排序,并打印对应的数据。根据排序规则,"Charlie" 的数据排在最前面,"Alice" 的数据排在中间,"Bob" 的数据排在最后面。
2.当需要自定义 TreeMap 的排序规则时,可以传入自定义的比较器(Comparator)。比较器是一个实现了 Comparator 接口的类,其中定义了一个 compare 方法,用于比较两个键的大小关系。
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
// Getters and setters
@Override
public String toString() {
return name + ": " + score;
}
}
现在希望按照学生的分数从高到低进行排序。可以创建一个自定义比较器 ScoreComparator,并实现其 compare 方法:
import java.util.Comparator;
public class ScoreComparator implements Comparator<Student> {
@Override
public int compare(Student student1, Student student2) {
return Integer.compare(student2.getScore(), student1.getScore());
}
}
在上述比较器中,我们通过比较学生对象的分数来确定它们的顺序。如果第一个学生的分数大于第二个学生的分数,则返回负值;如果第一个学生的分数小于第二个学生的分数,则返回正值;如果两个学生的分数相等,则返回零。
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
TreeMap<Student, String> treeMap = new TreeMap<>(new ScoreComparator());
treeMap.put(new Student("Alice", 85), "Data A");
treeMap.put(new Student("Bob", 92), "Data B");
treeMap.put(new Student("Charlie", 76), "Data C");
// 遍历输出
for (Student student : treeMap.keySet()) {
System.out.println(student.toString() + ": " + treeMap.get(student));
}
// 输出结果:
// Bob: 92: Data B
// Alice: 85: Data A
// Charlie: 76: Data C
}
}
在上述示例中,我们通过传入 ScoreComparator 来创建 TreeMap 实例,并根据分数的大小顺序进行排序。最终,"Bob" 的数据排在最前面,"Alice" 的数据排在中间,"Charlie" 的数据排在最后面。