TreeSet 集合类是Set的子类
固有保持数据不重复的属性,除此之外还有一个独有的功能就是排序
当然常见的Integer,String类中java都将其比较机制写的很完善了
但对于自定义类而言 ,想要去排序就要自己去实现了
假设录入一个 Person类 (new Person(“aa”,100))其属性为姓名和年龄
假设要求我需要对集合中Person的年龄进行排序的话 我们该怎么办呢?
TreeSet集合排序和保证元素唯一的原理
别着急 下面我们介绍一下Comparbale接口
实现这个接口就要重写 public int compareTo(Object o)方法
返回值是一个int值
对于这个方法有如下特性
前提保证返回值为固定值
1.当返回值为0 表示不存入集合
2.当返回值为正数 表示存入集合(功能为按照你存的顺序 正向存储)
3.当返回值为负数 表示存入集合(功能为按照你存的顺序 逆向存储)
至于为什么 下面我就介绍一下TreeSet中底层的实现算法二叉树
二叉树的实现就是说
第一个进来的数据 (对象)作为根
然后随后进来的对象依次与根进行比较
如果小于对象就放左边
如果大于对象就放右边
如果相等就不存储
希望这张图能更加深理解
这是重写了compareTo方法来比较年龄
所以返回从左开始 13 23 33 43
这是通过先比较名字的长度 然后再去比较名字的内容(跟拼音和笔画没有关系 全是靠Unicode编码实现的) 最后比较年龄
public class Person implements Comparable {
//......之前的属性和行为省略
/*@Override
//按照年龄排序
public int compareTo(Person o) {
int num = this.age - o.age;//年龄是比较的主要条件
return num == 0 ? this.name.compareTo(o.name) : num;//姓名是比较的次要条件
}*/
/*@Override
//按照姓名排序
public int compareTo(Person o) {
int num = this.name.compareTo(o.name);//姓名是主要条件
return num == 0 ? this.age - o.age : num;//年龄是次要条件
}*/
/*
* aaa
* bbb
*/
public int compareTo(Person o) {
int length = this.name.length() - o.name.length();//比较长度为主要条件
int num = length == 0 ? this.name.compareTo(o.name) : length;//比较内容为次要条件
return num == 0 ? this.age - o.age : num;//比较年龄为次要条件
}
}
TreeSet实现排序的第二种原理
比较器 原理其实和第一种差不多 稍微改变的只是代码 方便对于java已有排序的类进行改进(Integer ,String之类)
自定义比较器代码
1.实现Comparator的接口
2.重写compare方法 (由于每个类都是Object的子类 所以不需要重写equals方法)
class CompareByLen /*extends Object*/ implements Comparator {
@Override
public int compare(String s1, String s2) {//按照字符串的长度比较
int num = s1.length() - s2.length();//长度为主要条件
return num == 0 ? s1.compareTo(s2) : num;//内容为次要条件
}
}
3.最后在把比较器当作引用参数传递给TreeSet
TreeSet ts = new TreeSet<>(new CompareByLen());//Comparator c = new CompareByLen();
具体代码:
import java.util.Comparator;
import java.util.TreeSet;
import com.heiam.bean.Person;
public class Demo3_TreeSet {
/**
* @param args
* TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一
* 当compareTo方法返回0的时候集合中只有一个元素
* 当compareTo方法返回正数的时候集合会怎么存就怎么取
* 当compareTo方法返回负数的时候集合会倒序存储
*/
public static void main(String[] args) {
//需求:将字符串按照长度排序
TreeSet ts = new TreeSet<>(new CompareByLen());//Comparator c = new CompareByLen();
ts.add("aaaaaaaa");
ts.add("z");
ts.add("wc");
ts.add("nba");
ts.add("cba");
System.out.println(ts);
}
}
class CompareByLen /*extends Object*/ implements Comparator {
@Override
public int compare(String s1, String s2) {//按照字符串的长度比较
int num = s1.length() - s2.length();//长度为主要条件
return num == 0 ? s1.compareTo(s2) : num;//内容为次要条件
}
}
下面谈两种比较方法的区别
一丶自然排序(Comparable)
1.TreeSet中的add方法会自动把传入的对象提升为Comparable类型(如果没有提升的话 就会报出类型转换异常)
2.调用传入对象中的comparaTo()方法和集合中已有的对象作比较
3.根据comparaTo()方法的返回值的结果进行存储
二丶比较器Comparator< E >
1.创建TreeSet对象的时候可以传入一个比较器Comparator< E >
2.如果传入Comparator< E >d的子类对象,那么TreeSet就会按照比较器中的比较顺序排序
3.add()方法是自动调用Comparator< E >中compare方法
两种方式的区别
1.自然排序 TreeSet的无参构造
2.比较器排序 TreeSet的有参构造(参数为Comparator< E >)
小练习1.保留重复 并且排序
由于都知道要储存重复数据 需要用到ArrayList来存储
如果排序则需要TreeSet
import java.util.ArrayList;
import java.util.Comparator;
import java.util.TreeSet;
public class Main{
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("b");
list.add("b");
list.add("a");
list.add("a");
list.add("a");
System.out.println(list);
sort(list);
System.out.println(list);
}
public static void sort(ArrayList list) {
//匿名内部类!!!!
TreeSet ts = new TreeSet<>(
new Comparator(){
@Override
public int compare(String s1, String s2) {
int num = s1.compareTo(s2);
return num == 0 ? 1 : num;
}
});
ts.addAll(list);
list.clear();
list.addAll(ts);
}
}
如果不用匿名内部类的话 感觉比较复杂不是很方便
public class Main{
public static void main(String[] args) {
TreeSet ts = new TreeSet<>(new Comcom());//Comparator c = new CompareByLen();
}
}
class Comcom implements Comparator{
@Override
public int compare(String s1, String s2) {
int num = s1.compareTo(s2);
return num == 0 ? 1 : num;
}
}
打印的结果
啊