59- TreeMap

TreeMap 是 Java 中的一种集合类,它实现了 SortedMap 接口,提供了基于红黑树的有序映射。与普通的 HashMap 不同,TreeMap 中的键值对是按照键的顺序进行排序的。

一、TreeMap 特点

  1. 有序性:TreeMap 中的元素按照键的顺序进行排序,并且可以根据键进行范围查找。
  2. 基于红黑树:TreeMap 底层使用红黑树(自平衡二叉查找树)来组织键值对。红黑树保持了键的有序性,并保证了插入、删除和查找操作的较好性能(近似 O(log n))。
  3. 自然顺序与自定义顺序:TreeMap 可以根据键的自然顺序或者通过自定义的比较器进行排序。如果键实现了 Comparable 接口,那么将使用键的自然顺序;否则,需要在构造 TreeMap 对象时传入一个比较器来指定排序规则。
  4. 高效的操作: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" 的数据排在最后面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值