【Java】TreeMap

TreeMap 学习完毕后,整个的 Map集合 也就学习完毕了。

在整个Map体系中,其实还有 HashtableProperties 这两个集合,由于这两个集合会有跟 IO 相关的方法,因此当我们学完IO后再去学习这两个集合。

关于 TreeMap 我们同样没有什么额外的新的方法学习,只需要知道它本身的特点和底层原理就行了。

image-20240428125807956

一、特点

TreeMapTreeSet 底层原理一样,都是红黑树结构。

TreeMap 所有的特点也是由键决定的:不重复、无索引、可排序(对键进行排序)。

PS:默认按照键的从小到大进行排序,也可以自己规定键的排序规则。

代码的书写跟 TreeSet 是一样的

  • 实现 Comparable接口,指定比较规则。
  • 创建集合时传递 Comparator 比较器对象,指定比较规则。

如果第一种和第二种同时存在,那么以第二种为准。


二、练习一

需求1:
    键:整数表示id
    值:字符串表示商品名称
    要求1:按照id的升序排列
    要求2:按照id的降序排列

运行以下代码,发现它默认是按照 id 升序排列的

//1.创建集合对象
TreeMap<Integer,String> tm = new TreeMap<>();

//2.添加元素
tm.put(5,"可恰可乐");
tm.put(4,"雷碧");
tm.put(3,"九个核桃");
tm.put(2,"康帅傅");
tm.put(1,"粤利粤");

//3.打印集合
System.out.println(tm); // {1=粤利粤, 2=康帅傅, 3=九个核桃, 4=雷碧, 5=可恰可乐}

跟进 Integer,可以发现它也是实现了 Comparable接口 的。

image-20240428131906830

我们找到它重写的 compareTo 方法,可以发现在这个里面它其实已经制定了排序的规则,这个规则就是升序排列

image-20240428131953103

跟进 compare(),可以发现这个方法里面就是一个三元运算符。

image-20240428132155197

此时我们就知道了 IntegerDouble 等默认都是按照升序排列的。而我们在这里存的键就是 Integer,因此它就默认按照升序排列了。

String 是按照字母在 ASCII码表 中对应的数字升序进行排列的,而且是从首字母开始,一个一个往后比较。


题目还有第二个需求:按照 id 降序排列。此时默认的方式就已经不能满足我们的需求了,就可以使用第二种方式:在创建集合对象的时候,小括号中可以传递比较器的对象。

TreeMap<Integer,String> tm = new TreeMap<>(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        //o1:当前要添加的元素
        //o2:表示已经在红黑树中存在的元素
        return o2 - o1;
    }
});

三、练习二

需求2:
    键:学生对象
    值:籍贯
    要求:按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。

测试类

//1.创建集合
TreeMap<Student,String> tm = new TreeMap<>();

//2.创建三个学生对象
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("lisi",24);
Student s3 = new Student("wangwu",25);

//3.添加元素
tm.put(s1,"江苏");
tm.put(s2,"天津");
tm.put(s3,"北京");

//4.打印集合
System.out.println(tm);

如果不指定排序规则,就会直接报错。

image-20240428141754654

Student.java

public class Student implements Comparable<Student>{
    private String name;
    private int age;

    // 无参构造、有参构造、get、set方法
    
    @Override
    public int compareTo(Student o) {
        //按照学生年龄的升序排列,年龄一样按照姓名的字母排列,同姓名年龄视为同一个人。

        //this:表示当前要添加的元素
        //o:表示已经在红黑树中存在的元素

        //返回值:
        //负数:表示当前要添加的元素是小的,存左边
        //正数:表示当前要添加的元素是大的,存右边
        //0:表示当前要添加的元素已经存在,舍弃

        int i = this.getAge() - o.getAge();
        i = i == 0 ? this.getName().compareTo(o.getName()) : i;
        return i;
    }
}

四、利用 TreeMap 进行排序

需求:
字符串“aababcabcdabcde”
请统计字符串中每一个字符出现的次数,并按照以下格式输出
输出结果:
a(5)b(4)c(3)d(2)e(1

由于利用计数器的方式进行统计有一定的弊端,因此我们就引出来一个新的思想:利用 Map集合 进行统计。

利用 Map集合 进行统计有两种方式:1、HashMap;2、TreeMap

它们的键都表示:要统计的内容;值:表示要统计的次数。

如果题目中没有要求对结果进行排序,默认使用 HashMap,因为它的效率是最高的。

但是如果题目要求对结果进行排序,请使用 TreeMap

由结果可知,这里应该使用 TreeMap

//1.定义字符串
String s = "aababcabcdabcde";

//2.创建集合
TreeMap<Character,Integer> tm = new TreeMap<>();

//3.遍历字符串得到里面的每一个字符
for (int i = 0; i < s.length(); i++) {
    char c = s.charAt(i);
    //拿着c到集合中判断是否存在
    //存在,表示当前字符又出现了一次
    //不存在,表示当前字符是第一次出现
    if(tm.containsKey(c)){
        //存在
        //先把已经出现的次数拿出来
        int count = tm.get(c);
        //当前字符又出现了一次
        count++;
        //把自增之后的结果再添加到集合当中
        tm.put(c,count);
    }else{
        //不存在
        tm.put(c,1);
    }
}

//4.遍历集合,并按照指定的格式进行拼接
// a(5)b(4)c(3)d(2)e(1)
//StringBuilder sb = new StringBuilder();
//tm.forEach((key, value)->sb.append(key).append("(").append(value).append(")"));

StringJoiner sj = new StringJoiner("","","");
// 非字符串的内容需要 + ""
tm.forEach((key, value)->sj.add(key + "").add("(").add(value + "").add(")"));

System.out.println(sj);

五、总结

1、TreeMap集合 的特点是什么样的?

  • 键:不重复、无索引、可排序
  • 底层基于红黑树进行实现,增删改查性能较好

2、TreeMap集合 排序的两种方式

  • 默认的排序规则:实现 Comparable接口,指定比较规则
  • 创建集合时传递Comparator比较器对象,指定比较规则

例如字符串、Integer中默认的排序规则有时候就不能满足我们的需求了。

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值