Java TreeSet和TreeMap集合
TreeSet
1、TreeSet集合底层实际上是一个TreeMap
2、TreeMap集合底层是一个二叉树。
3、放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。
4、TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。
称为:可排序集合。
public class TreeSetTest02 { public static void main(String[] args) { // 创建一个TreeSet集合 TreeSet<String> ts = new TreeSet<>(); // 添加String ts.add("zhangsan"); ts.add("lisi"); ts.add("wangwu"); ts.add("zhangsi"); ts.add("wangliu"); // 遍历 for(String s : ts){ // 按照字典顺序,升序! System.out.println(s); } TreeSet<Integer> ts2 = new TreeSet<>(); ts2.add(100); ts2.add(200); ts2.add(900); ts2.add(800); ts2.add(600); ts2.add(10); for(Integer elt : ts2){ // 升序! System.out.println(elt); } } }
对自定义的类型来说,TreeSet可以排序吗?
以下程序中对于Person类型来说,无法排序。因为没有指定Person对象之间的比较规则。
谁大谁小并没有说明啊。
以下程序运行的时候出现了这个异常:
java.lang.ClassCastException:
class com.bjpowernode.javase.collection.Person
cannot be cast to class java.lang.Comparable
出现这个异常的原因是:
Person类没有实现java.lang.Comparable接口。
package com.bjpowernode.javase.collection; import java.util.TreeSet; public class TreeSetTest04 { public static void main(String[] args) { Customer c1 = new Customer(32); Customer c2 = new Customer(20); Customer c3 = new Customer(30); Customer c4 = new Customer(25); // 创建TreeSet集合 TreeSet<Customer> customers = new TreeSet<>(); // 添加元素 customers.add(c1); customers.add(c2); customers.add(c3); customers.add(c4); // 遍历 for (Customer c : customers){ System.out.println(c); } } } // 放在TreeSet集合中的元素需要实现java.lang.Comparable接口。 // 并且实现compareTo方法。equals可以不写。 class Customer implements Comparable<Customer>{ int age; public Customer(int age){ this.age = age; } // 需要在这个方法中编写比较的逻辑,或者说比较的规则,按照什么进行比较! // k.compareTo(t.key) // 拿着参数k和集合中的每一个k进行比较,返回值可能是>0 <0 =0 // 比较规则最终还是由程序员指定的:例如按照年龄升序。或者按照年龄降序。 @Override public int compareTo(Customer c) { // c1.compareTo(c2); // this是c1 // c是c2 // c1和c2比较的时候,就是this和c比较。 /*int age1 = this.age; int age2 = c.age; if(age1 == age2){ return 0; } else if(age1 > age2) { return 1; } else { return -1; }*/ //return this.age - c.age; // =0 >0 <0 return c.age - this.age; } public String toString(){ return "Customer[age="+age+"]"; } }
package com.bjpowernode.javase.collection; import java.util.TreeSet; /* 先按照年龄升序,如果年龄一样的再按照姓名升序。 */ public class TreeSetTest05 { public static void main(String[] args) { TreeSet<Vip> vips = new TreeSet<>(); vips.add(new Vip("zhangsi", 20)); vips.add(new Vip("zhangsan", 20)); vips.add(new Vip("king", 18)); vips.add(new Vip("soft", 17)); for(Vip vip : vips){ System.out.println(vip); } } } class Vip implements Comparable<Vip>{ String name; int age; public Vip(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Vip{" + "name='" + name + '\'' + ", age=" + age + '}'; } /* compareTo方法的返回值很重要: 返回0表示相同,value会覆盖。 返回>0,会继续在右子树上找。【10 - 9 = 1 ,1 > 0的说明左边这个数字比较大。所以在右子树上找。】 返回<0,会继续在左子树上找。 */ @Override public int compareTo(Vip v) { // 写排序规则,按照什么进行比较。 if(this.age == v.age){ // 年龄相同时按照名字排序。 // 姓名是String类型,可以直接比。调用compareTo来完成比较。 return this.name.compareTo(v.name); } else { // 年龄不一样 return this.age - v.age; } } }
TreeSet集合中元素可排序的第二种方式:使用比较器的方式。
最终的结论:
放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:
第一种:放在集合中的元素实现java.lang.Comparable接口。
第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
Comparable和Comparator怎么选择呢?
当比较规则不会发生改变的时候,或者说当比较规则只有1个的时候,建议实现Comparable接口。
如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。
Comparator接口的设计符合OCP原则。
package com.bjpowernode.javase.collection; import java.util.*; /* java.util.Collection 集合接口 java.util.Collections 集合工具类,方便集合的操作。 */ public class CollectionsTest { public static void main(String[] args) { // ArrayList集合不是线程安全的。 List<String> list = new ArrayList<>(); // 变成线程安全的 Collections.synchronizedList(list); // 排序 list.add("abf"); list.add("abx"); list.add("abc"); list.add("abe"); Collections.sort(list); for(String s : list){ System.out.println(s); } List<WuGui2> wuGuis = new ArrayList<>(); wuGuis.add(new WuGui2(1000)); wuGuis.add(new WuGui2(8000)); wuGuis.add(new WuGui2(500)); // 注意:对List集合中元素排序,需要保证List集合中的元素实现了:Comparable接口。 Collections.sort(wuGuis); for(WuGui2 wg : wuGuis){ System.out.println(wg); } // 对Set集合怎么排序呢? Set<String> set = new HashSet<>(); set.add("king"); set.add("kingsoft"); set.add("king2"); set.add("king1"); // 将Set集合转换成List集合 List<String> myList = new ArrayList<>(set); Collections.sort(myList); for(String s : myList) { System.out.println(s); } // 这种方式也可以排序。 //Collections.sort(list集合, 比较器对象); } } class WuGui2 implements Comparable<WuGui2>{ int age; public WuGui2(int age){ this.age = age; } @Override public int compareTo(WuGui2 o) { return this.age - o.age; } @Override public String toString() { return "WuGui2{" + "age=" + age + '}'; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?