TreeSet的排序方式

server/2024/11/12 13:24:53/

一.TreeSet的特点:


二.TreeSet对象排序练习题:

需求:利用TreeSet存储整数并进行排序

java">package com.itheima.a06mySet;
​
import java.util.TreeSet;
​
public class A05_TreeSetDemo1 {public static void main(String[] args) {//1.创建TreeSet集合对象TreeSet<Integer> ts=new TreeSet<>();//注:泛型如果是基本数据类型的话要用包装类
​//2.添加元素ts.add(4);ts.add(5);ts.add(1);ts.add(3);ts.add(2);
​//3.打印集合System.out.println(ts);/* 运行结果为[1, 2, 3, 4, 5]已经排好序了,默认排序规则为从小到大*/}
}
 

对刚才的集合进行遍历:

  • 迭代器:
    java">package com.itheima.a06mySet;
    ​
    import java.util.Iterator;
    import java.util.TreeSet;
    ​
    public class A05_TreeSetDemo1 {public static void main(String[] args) {//1.创建TreeSet集合对象TreeSet<Integer> ts=new TreeSet<>();//注:泛型如果是基本数据类型的话要用包装类
    ​//2.添加元素ts.add(4);ts.add(5);ts.add(1);ts.add(3);ts.add(2);
    ​//3.遍历集合Iterator<Integer> it=ts.iterator();while (it.hasNext()){Integer i = it.next();//这里i也可以用int型,因为JDK5有自动装箱和自动拆箱的功能System.out.print(i+",");}/* 遍历结果为1,2,3,4,5,*/}
    }
     
  • 增强for:
    java">package com.itheima.a06mySet;
    ​
    import java.util.TreeSet;
    ​
    public class A05_TreeSetDemo1 {public static void main(String[] args) {//1.创建TreeSet集合对象TreeSet<Integer> ts=new TreeSet<>();//注:泛型如果是基本数据类型的话要用包装类
    ​//2.添加元素ts.add(4);ts.add(5);ts.add(1);ts.add(3);ts.add(2);
    ​//3.遍历集合for (Integer t : ts) {System.out.print(t+",");}/* 遍历结果为1,2,3,4,5,*/}
    }
    ​

  • Lambda表达式:

未使用Lambda表达式前:

java">package com.itheima.a06mySet;
​
import java.util.TreeSet;
import java.util.function.Consumer;
​
public class A05_TreeSetDemo1 {public static void main(String[] args) {//1.创建TreeSet集合对象TreeSet<Integer> ts=new TreeSet<>();//注:泛型如果是基本数据类型的话要用包装类
​//2.添加元素ts.add(4);ts.add(5);ts.add(1);ts.add(3);ts.add(2);
​//3.遍历集合ts.forEach(new Consumer<Integer>() { //forEach是一个方法,底层用了增强for遍历集合@Override //重写了Consumer接口的抽象方法public void accept(Integer i) {System.out.print(i+",");}});/* 遍历结果为1,2,3,4,5,*/}
}
使用Lambda表达式后:
java">package com.itheima.a06mySet;
​
import java.util.TreeSet;
​
public class A05_TreeSetDemo1 {public static void main(String[] args) {//1.创建TreeSet集合对象TreeSet<Integer> ts=new TreeSet<>();//注:泛型如果是基本数据类型的话要用包装类
​//2.添加元素ts.add(4);ts.add(5);ts.add(1);ts.add(3);ts.add(2);
​//3.遍历集合ts.forEach(i ->System.out.print(i+","));/* 遍历结果为1,2,3,4,5,*/}
}

三.TreeSet集合默认的规则:

1.非自定义数据类型排序:

例如字符串排序:"aaa","aba","qwer","ab","cd"

排序后为:"aaa","ab","aba","cd","qwer"(默认是升序排序)

从第一个开始比,只要发现大的就停止比较,对于"ab"和"aba","ab"前两个和"aba"一样,"ab"在第三个

比"aba"少一个字母,默认比"aba"小。

2.自定义类型排序:

如:需求:创建TreeSet集合,并添加3个学生对象

学生对象属性:姓名,年龄。

要求按照学生的年龄进行排序

同年龄按照姓名字母排列(暂不考虑中文)

同姓名,同年龄认为是同一个人

错解:

Student类:

java">package com.itheima.a06mySet;
​
public class Student {private String name;private int age;
​
​public Student() {}
​public Student(String name, int age) {this.name = name;this.age = age;}
​/*** 获取* @return name*/public String getName() {return name;}
​/*** 设置* @param name*/public void setName(String name) {this.name = name;}
​/*** 获取* @return age*/public int getAge() {return age;}
​/*** 设置* @param age*/public void setAge(int age) {this.age = age;}
​public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}

测试类:

java">package com.itheima.a06mySet;
​
import java.util.TreeSet;
​
public class A05_TreeSetDemo2 {public static void main(String[] args) {//1.创建3个学生对象Student s1=new Student("zhangsan",23);Student s2=new Student("lisi",24);Student s3=new Student("wangwu",25);
​//2.创建集合对象TreeSet<Student> ts=new TreeSet<>();
​//3.添加元素ts.add(s1);ts.add(s2);ts.add(s3);
​//4.打印集合System.out.println(ts);}
}
​

打印结果会报错,因为s1,s2和s3都是自定义的类型,此时没有指明比较规则,添加元素的时候也就无法进行比较再添加,在添加元素时就已经出错了。


正解:需要指明比较规则。


四.TreeSet的两种比较方式:(如果两种比较方式都存在,则以方式二为准)

方式一:默认排序/自然排序Javabean类实现Comparable接口指定比较规则

接刚才的例子:需要Student类实现Comparable接口,重写里面的抽象方法,再指定比较规则

Student类:

java">package com.itheima.a06mySet;
​
public class Student implements Comparable<Student>{ //此时已经明确比较排序的就是Student型// 用了接口Comparable,本例中要写比较规则,所以重写方法
​private String name;private int age;
​
​public Student() {}
​public Student(String name, int age) {this.name = name;this.age = age;}
​/*** 获取* @return name*/public String getName() {return name;}
​/*** 设置* @param name*/public void setName(String name) {this.name = name;}
​/*** 获取* @return age*/public int getAge() {return age;}
​/*** 设置* @param age*/public void setAge(int age) {this.age = age;}
​public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
​@Overridepublic int compareTo(Student o) {//指定排序规则/* 只看年龄要按照年龄的升序进行排序*/int result=this.getAge() - o.getAge();return result;}
​/* 不需要重写hashCode和equals方法因为hashCode和equals方法是和哈希表有关的而TreeSet底层是红黑树*/
}
​

注:在这种重写后的方法下才有相同的不存的效果,因为底层是红黑树。自己写的一般没有相同的不存的效果。

测试类:

java">package com.itheima.a06mySet;import java.util.TreeSet;public class A05_TreeSetDemo2 {public static void main(String[] args) {//1.创建3个学生对象Student s1=new Student("zhangsan",23);Student s2=new Student("lisi",24);Student s3=new Student("wangwu",25);//2.创建集合对象TreeSet<Student> ts=new TreeSet<>();//3.添加元素ts.add(s3);ts.add(s2);ts.add(s1);//4.打印集合System.out.println(ts);/* 运行结果为[Student{name = zhangsan, age = 23}, Student{name = lisi, age = 24},Student{name = wangwu, age = 25}]已经指明了比较规则,此时可正常运行*/}
}

解释Student类里的compareTo方法:

先添加25(s3),要变黑,因为是根节点。再添加24(s2),此时25(s3)是o,24(s2)是this:

添加后,刚好符合红黑树规则:

再添加23(s1),此时23(s1)是this。注:先和25(s3)比较,因为25(s3)是根节点(添加元素时一定是先和根节点进行比较),此时25(s3)是o。

经过比较后23(s1)存左边,但左边已经有24(s2),因此继续调用compareTo方法进行比较添加。

此时24(s2)是o,23(s1)是this-->经过比较添加后为:

但此时不符合红黑树规则,需要进行一系列改正操作。s1为非根节点,s1的父为红色,叔叔为Nil即黑色,且s1是父的左孩子,因此进行3的操作,注:祖父为s3,右旋时不考虑叶子节点,结果为:

结果中叶子节点省略了

此时根节点变为24(s2),再添加元素时就是先和根节点24(s2)比较了


代码解释:

Student类:

java">package com.itheima.a06mySet;public class Student implements Comparable<Student>{ //此时已经明确比较排序的就是Student型// 用了接口Comparable,本例中要写比较规则,所以重写方法private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}@Override//this:表示当前要添加的元素//o:表示已经在红黑树中存在的元素/* 返回值:负数:表示当前要添加的元素是小的,就要存左边正数:表示当前要添加的元素是大的,就要存右边0:表示当前要添加的元素已经存在,此时要舍弃(因为TreeSet集合不重复)*/public int compareTo(Student o) {System.out.println("--------------------------------------");System.out.println("this:"+this);System.out.println("o:"+o);//指定排序规则/* 只看年龄要按照年龄的升序进行排序*/int result=this.getAge() - o.getAge();return result;}/* 不需要重写hashCode和equals方法因为hashCode和equals方法是和哈希表有关的而TreeSet底层是红黑树*/
}

测试类:

java">package com.itheima.a06mySet;import java.util.TreeSet;public class A05_TreeSetDemo2 {public static void main(String[] args) {//1.创建3个学生对象Student s1=new Student("zhangsan",23);Student s2=new Student("lisi",24);Student s3=new Student("wangwu",25);//2.创建集合对象TreeSet<Student> ts=new TreeSet<>();//3.添加元素ts.add(s3);ts.add(s2);ts.add(s1);//4.打印集合System.out.println(ts);}
}

运行结果为:

一开始先添加的25(s3),但一开始没有节点,因此第一次25(s3)自己和自己比较

25(s3)为根节点,因为第一次添加


方式二:比较器排序创建TreeSet对象时,传递比较器Comparator指定规则

(使用原则:默认使用第一种比较方式,如果第一种比较方式不能满足当前需求,就使用第二种比较方式。如字符串里的compareTo方法在idea底层是按照字母顺序进行排序的,如果此时想用别的方式排序,就需要进行大量操作,但太麻烦,因此就需要用第二种排序方式指定比较排序规则;再比如Integer型默认从小到大排,要想从大到小排,最好选第二种排序方式)

Comparator<T>属于函数式接口,可以改用Lambda表达式

例如:

需求:请自行选择比较器排序和自然排序两种方式;

要求:存入四个字符串,"c","ab","df","qwer"

按照长度排序,如果一样长则按照首字母排序

分析:字符串比较方式idea已经写好,虽然可以修改源码来定义自己的排序方式,但太麻烦,因此用比较器排序

java">package com.itheima.a06mySet;import java.util.Comparator;
import java.util.TreeSet;public class A06_TreeSetDemo3 {public static void main(String[] args) {//1.创建集合//o1:表示当前要添加的元素//o2:表示已经在红黑树中存在的元素//返回值规则:小的存左边,大的存右边,一样的不存//先定好规则再添加元素TreeSet<String> ts=new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//a.按照长度排序int i = o1.length() - o2.length();//b.如果一样长则按照首字母排序(即默认排序方式-->o1.compareTo(o2)),不一样长以长度为准即ii = i==0?o1.compareTo(o2):i;return i;}});//2.添加元素ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");//3.打印集合System.out.println(ts);//运行结果为[c, ab, df, qwer]}
}

注:compare是重写的方法的名字,compareTo是比较字符串用的方法。

改用Lambda表达式:

java">package com.itheima.a06mySet;import java.util.TreeSet;public class A06_TreeSetDemo3 {public static void main(String[] args) {//1.创建集合//o1:表示当前要添加的元素//o2:表示已经在红黑树中存在的元素//返回值规则:小的存左边,大的存右边,一样的不存TreeSet<String> ts=new TreeSet<>((o1,o2) -> {//a.按照长度排序int i = o1.length() - o2.length();//b.如果一样长则按照首字母排序(即默认排序方式-->o1.compareTo(o2)),不一样长以长度为准即ii = i==0?o1.compareTo(o2):i;return i;});//2.添加元素ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");//3.打印集合System.out.println(ts);//运行结果为[c, ab, df, qwer]}
}

五.TreeSet对象排序练习题:

题目如下:

解:

Student类:
java">package a32mySet;public class Student implements Comparable<Student>{//姓名private String name;//年龄private int age;//语文成绩private int chinese;//数学成绩private int math;//英语成绩private int english;public Student() {}public Student(String name, int age, int chinese, int math, int english) {this.name = name;this.age = age;this.chinese = chinese;this.math = math;this.english = english;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}/*** 获取* @return chinese*/public int getChinese() {return chinese;}/*** 设置* @param chinese*/public void setChinese(int chinese) {this.chinese = chinese;}/*** 获取* @return math*/public int getMath() {return math;}/*** 设置* @param math*/public void setMath(int math) {this.math = math;}/*** 获取* @return english*/public int getEnglish() {return english;}/*** 设置* @param english*/public void setEnglish(int english) {this.english = english;}public String toString() {return "Student{name = " + name + ", age = " + age + ", chinese = " + chinese +", math = " + math + ", english = " + english + "}";}@Overridepublic int compareTo(Student o) {//求已有的人(this)的总分和要添加的人(o)的总分int sum1=this.getChinese()+this.getMath()+this.getEnglish();int sum2=o.getChinese()+o.getMath()+o.getEnglish();//总分做差int i=sum1-sum2;//1.先比总分,总分一样,比语文,总分不一样正常来i = i==0?this.getChinese()-o.getChinese():i;//2.语文一样比数学i = i==0?this.getMath()-o.getMath():i;//3.数学一样比英语(可省略,因为前面已经证明总分,数学和语文都一样了,那么英语必然一样,且一共就语数英三科)i = i==0?this.getEnglish()-o.getEnglish():i;//4.英语一样比年龄i = i==0?this.getAge()-o.getAge():i;//5.年龄一样比姓名i = i==0?this.getName().compareTo(o.getName()):i;/*当比到姓名时,说明除了姓名外其他属性都一样,如果姓名也一样,则代表属性都一样,且用到了方法compareTo,它的底层是红黑树,就不会添加,刚好做到了去重(String型属于idea已经写好的,他的compareTo方法可以直接用)*/return i;}
}
测试类:
java">package a32mySet;import java.util.TreeSet;public class A07_TreeSetDemo4 {public static void main(String[] args) {//1.创建学生对象Student s1=new Student("zhangsan",23,90,99,50);Student s2=new Student("lisi",24,90,98,50);Student s3=new Student("wangwu",25,95,100,30);Student s4=new Student("zhaoliu",26,60,99,70);Student s5=new Student("qianqi",26,70,80,70);//2.创建集合TreeSet<Student> ts=new TreeSet<>();//3.添加元素ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);//4.打印集合for (Student t : ts) {System.out.println(t);}}
}
运行结果:


六.总结:


七.单列集合使用场景:



http://www.ppmy.cn/server/102275.html

相关文章

Eureka原理与实践:构建高效的微服务架构

Eureka原理与实践&#xff1a;构建高效的微服务架构 Eureka的核心原理Eureka Server&#xff1a;服务注册中心Eureka Client&#xff1a;服务提供者与服务消费者 Eureka的实践应用集成Eureka到Spring Cloud项目中创建Eureka Server创建Eureka Client&#xff08;服务提供者&…

LabVIEW滚动轴承故障诊断系统

滚动轴承是多种机械设备中的关键组件&#xff0c;其性能直接影响整个机械系统的稳定性和安全性。由于轴承在运行过程中可能会遇到多种复杂的工作条件和环境因素影响&#xff0c;这就需要一种高效、准确的故障诊断方法来确保机械系统的可靠运行。利用LabVIEW开发的故障诊断系统&…

React使用useRef ts 报错

最近在写自己的React项目&#xff0c;我在使用useRef钩子函数的时候发现 TS2322: Type MutableRefObject<HTMLDivElement | undefined> is not assignable to type LegacyRef<HTMLDivElement> | undefined Type MutableRefObject<HTMLDivElement | undefined&g…

SDL库自适应窗口大小及遇到的坑

一、窗口尺寸改变大小时&#xff0c;视频卡住不动 网上介绍的方法有&#xff1a; 1&#xff1a;修改源码中的代码&#xff01; SDL_OnWindowResized中的SDL_WINDOWEVENT_SIZE_CHANGED更改为SDL_WINDOWEVENT_RESIZED 2&#xff1a;SDL_EventState(SDL_WINDOWEVENT, SDL_IGNORE…

Golang | Leetcode Golang题解之第343题整数拆分

题目&#xff1a; 题解&#xff1a; func integerBreak(n int) int {if n < 3 {return n - 1}quotient : n / 3remainder : n % 3if remainder 0 {return int(math.Pow(3, float64(quotient)))} else if remainder 1 {return int(math.Pow(3, float64(quotient - 1))) * …

C#多态_接口

接口是行为的抽象表现 关键字 interface 接口申明的规范 1.不包含成员变量 2.只包含&#xff0c;方法&#xff0c;属性&#xff0c;索引器&#xff0c;事件 3.成员不能被实现 4.成员可以不用写访问修饰符&#xff0c;不能是私有的&#xff08;不写默认是public也可以写pro…

c语言编程有什么难点

C语言编程面临的难点主要有1、指针的理解和使用、2、内存管理、3、复杂的数据结构实现、4、并发和多线程编程以及5、跨平台编程。指针是C语言中最具特色也最令人头疼的部分。它直接操作内存地址&#xff0c;能够提供强大但复杂的数据管理方式。正确而高效地使用指针&#xff0c…

记处理微前端的一些问题

主子应用样式 因为子应用是是后加载的 所以如果柱应用和子应用有重的 会以子应用为准、 需要我们将主应用的样式权重提高或尽量避免重复 我这里还遇到一个问题就是主应用使用rem定义的样式加载子应用会失效 解决办法就是没定义默认字体html{ font-size: 16px; } 主应用重新加载…