【Java集合框架】3 - 11 TreeMap 集合

§3-11 TreeMap 集合

3-11.1 特点与底层原理

TreeMap 位于 java.util 包下,是 Map 的一个实现类,其中没有独特的方法,一般直接使用 Map 中的方法即可。

TreeMap 特点

  • TreeMapTreeSet 一样,在底层采用红黑树存储数据;
  • 由键决定特点:可排序、无重复、无索引;
  • 可排序:指的是对键进行排序;
  • 默认对键升序排序,也可自定义排序规则;

比较规则:同 TreeSet 中的自定义比较规则方法

  • 默认使用:Java Bean 类实现 Comparable 接口并重写 compareTo 方法;
  • 覆盖使用:往构造器中传入 Comparator 接口的实现类对象,重写 compare 方法(在默认方式不能满足需求时使用);

两种方式同时存在时,则会优先采用 Comparator 中的 compare 方法排序。

3-11.2 案例演示

需求一:键表示 ID,值表示商品名称。要求按照 ID 升序、降序排列商品。

TreeMap<Integer, String> goods = new TreeMap<>();

goods.put(0, "粤利粤");
goods.put(2, "康帅傅");
goods.put(1, "脉劫");
goods.put(3, "雷碧");

//默认升序
System.out.println(goods);

//键表示 ID,值表示商品名称。要求按照 ID 升序、降序排列商品
TreeMap<Integer, String> goods = new TreeMap<>((o1, o2) -> o2 - o1);

goods.put(0, "粤利粤");
goods.put(2, "康帅傅");
goods.put(1, "脉劫");
goods.put(3, "雷碧");

//降序
System.out.println(goods);

得到结果(降序):

{3=雷碧, 2=康帅傅, 1=脉劫, 0=粤利粤}

需求二:键表示学生对象,值表示籍贯。要求按照学生年龄升序排列,年龄相等则按姓名首字母排列,同名同年视为同一个人。

//Java Bean 类
public class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    public String toString() {
        return name + "(" + age + ")";
    }

    @Override
    public int compareTo(Student o) {
        //要求按照学生年龄升序排列,年龄相等则按姓名首字母排列,同名同年视为同一个人
        int i = this.getAge() - o.getAge();
        i = i == 0 ? this.getName().compareTo(o.getName()) : i;

        return i;
    }
}

测试类中

TreeMap<Student, String> map = new TreeMap<>();

Student s1 = new Student("Zhang San", 23);
Student s2 = new Student("Zhang Ban", 23);
Student s3 = new Student("Wang Wu", 25);
Student s4 = new Student("Li Si", 24);

map.put(s1, "Guangdong");
map.put(s2, "Guangxi");
map.put(s3, "Fujian");
map.put(s4, "Beijing");

System.out.println(map);

得到结果:

{Zhang Ban(23)=Guangxi, Zhang San(23)=Guangdong, Li Si(24)=Beijing, Wang Wu(25)=Fujian}

**需求三 **:现有字符串 "aababcabcdabcde",要求统计字符串中每一个字符出现的次数,并按照所示格式输出:a(5) b(4) c(3) d(2) e(1)

这一需求与上一节中使用 HashMap 统计的需求相似,都是对不能预先确定种类数的内容进行统计,这时考虑使用 Map 集合统计。

使用 Map 统计,键存储统计内容,值存储统计个数。

HashMapTreeMap 都可以完成统计,但前者适用于无需对结果排序的统计,而后者适用于需要对结果排序的统计。

本需求是对字符作统计,而示例中明确要求统计结果需要排序,则考虑使用 TreeMap 排序。

String str = "aababcabcdabcde";
Map<Character, Integer> stats = new TreeMap<>();

for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    if (stats.containsKey(c)) {
        //有
        int val = stats.get(c);
        stats.put(c, ++val);
    } else {
        //没有
        stats.put(c, 1);
    }
}

//输出结果,使用 StringJoiner
StringJoiner sj = new StringJoiner(" ");
stats.forEach((key, val) -> sj.add(key + "(" + val + ")"));
System.out.println(sj);

得到结果:

a(5) b(4) c(3) d(2) e(1) 
posted @ 2023-08-11 18:42  Zebt  阅读(28)  评论(0)    收藏  举报