TreeSet描述的是Set的一个变体--可实现排序功能的集合。将对象插入到TreeSet中时,会按照某种规则将对象插入到一个有序序列中,以保证TreeSet集合中的对象序列保持"升序"排列。
TreeSet中的排序方法是根据什么确定对象之间的“大小”关系呢?
所有可能排序的类都实现了java.lang.Comparable接口,该接口中只有一个抽象方法:
public int compareTo(Object obj)
注意:用户在实现compareTo()方法确定比较逻辑时,比较结果应该和equals90方法比较的结果一致。
TreeSet的用法:
TreeSet是依靠TreeMap来实现的
TreeSet是一个有序集合,她的元素 按照升序排列,默认是按照自然顺序排列,也就是说TreeSet中的对象元素需要实现Comparable接口。
TreeSet类中跟HashSet类一样也没有get()方法来获取列表中的元素,所以也只能通过迭代器方法来获取。
1,
//TreeSet的范例
TreeSet ts = new TreeSet();
ts.add("bddda");
ts.add("abd");
ts.add("zgagl");
ts.add("Dujlg");
ts.add("acb");
Iterator it= ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
运行结果:
Dujlg
abd
acb
bddda
zgagl
很明显,输出结果是排好序的,
结论:TreeSet会自动进行排序
2,
知识点:相同的对象不会重复存储,也就是TreeSet集合里的值不重复。
存储到TreeSet集合的元素必须具有可比性,如果元素自身不具可比性,那么需要让集合自身具备可比性。如果元素有可比性,并且集合也有可比性,那么以集合(比较器)为主。
package fighting;
import java.util.Iterator;
import java.util.TreeSet;
/**
* Set:无序,不可以重复元素。
* |--HashSet:数据结构是哈希表。线程是非同步的。
* | 保证元素唯一性的原理:判断元素的hashcode值是否相同。
* | 如果相同,还会继续判断元素的equals方法,是否为true。
* |--TreeSet:可以对Set集合中的元素进行排序。底层的数据结构是二叉树。
* 保证元素唯一性的依据:compareTo方法return 0
*
* TreeSet排序的第一种方式:让元素自身具备比较性。
* 元素需要实现Comparable接口,覆盖compareTo方法。
* 这种方式也称为元素的自然顺序,或者叫做默认顺序。
*
* TreeSet的第二种排序方式:当元素自身不具备比较性时,
* 或者具备比较性不是所需要的,这时就需要让集合自身具备比较性。
* 怎么实现呢?在集合初始化时,就有了比较方式。
*
* 如果两种方式都具备了,那么以比较器为主
*/
public class TreeSetDemo {
/**
* 往TreeSet中存储自定义对象,按照学生的的年龄排序
*/
public static void main(String[] args) {
/**
* TreeSet集合存储对象时,要自动排序的,所以要保证存储的对象具有可比性,
* 使得对象实现Comparable接口即可
*/
TreeSet ts = new TreeSet();
/**
* 技巧:如果想要按原样输出TreeSet集合的值,
* 只要把compareTo方法返回值设为固定值1即可。
* 原因:根据二叉树原理,每次都会让根节点的右节点存储
*/
ts.add(new Student("zhangsan",32));//①
ts.add(new Student("lisi",20));//②
ts.add(new Student("wanglu",21));//③
ts.add(new Student("wanglu",21));//④
ts.add(new Student("Dujlg",22));//⑤
ts.add(new Student("Dujlg",19));//⑥
ts.add(new Student("aaa",19));//⑦
ts.add(new Student("zhaoliu",19));//⑧
Iterator it= ts.iterator();
while(it.hasNext()){
Student stu = (Student)it.next();
System.out.println(stu.getName()+":"+stu.getAge());
}
}
}
class Student implements Comparable{
private String name;
private int age;
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;
}
//对象实现Comparable接口的compareTo方法,就具备了可比性
public int compareTo(Object obj) {
if(!(obj instanceof Student)){
throw new RuntimeException("不是学生对象");
}
Student s = (Student)obj;
System.out.println(this.name+" compareTo "+s.name);
if(this.age > s.age){
return 1;
}
if(this.age==s.age){
//注意:如果年龄相同,还要比较姓名是不是相同,只有所有属性都相同,对象才相等
return this.name.compareTo(s.name);
}
return -1;
}
}
运行结果:
Dujlg:19
aaa:19
zhaoliu:19
lisi:20
wanglu:21
Dujlg:22
zhangsan:32
结果是先按年龄排序,年龄相同,再比较姓名,按姓名排序。
3,在创建TreeSet对象时传递一个比较器来实现自己的排序方式
结论:当元素自身不具备比较性,或者具备的比较性不是所需要的,这时需要让容器自身具备比较性。
package fighting;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo2 {
/**
* 当元素自身不具备比较性,或者具备的比较性不是所需要的,
* 这时需要让容器自身具备比较性。
* 定义比较器,将比较器对象传给TreeSet集合的构造方法
*
*/
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompare());
/**
* 技巧:如果想要按原样输出TreeSet集合的值,
* 只要把compareTo方法返回值设为固定值1即可。
* 原因:根据二叉树原理,每次都会让根节点的右节点存储
*/
ts.add(new Student("zhangsan",32));//①
ts.add(new Student("lisi",20));//②
ts.add(new Student("wanglu",21));//③
ts.add(new Student("wanglu",21));//④
ts.add(new Student("Dujlg",22));//⑤
ts.add(new Student("Dujlg",19));//⑥
ts.add(new Student("aaa",19));//⑦
ts.add(new Student("zhaoliu",19));//⑧
Iterator it= ts.iterator();
while(it.hasNext()){
Student stu = (Student)it.next();
System.out.println(stu.getName()+":"+stu.getAge());
}
}
}
class MyCompare implements Comparator{
public int compare(Object o1,Object o2){
Student s1 = (Student)o1;
Student s2 = (Student)o2;
//如果名称相同,还要比较年龄是否相同,因为年龄是int型,没有compareTo方法,所以封装成Integer对象
int num = s1.getName().compareTo(s2.getName());
if(num==0){
num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}
运行结果:
Dujlg:19
Dujlg:22
aaa:19
lisi:20
wanglu:21
zhangsan:32
zhaoliu:19
4,
结论:字符串长度方法返回的是基本类型,没有compareTo方法,为了使用这个方法,长度封装成Integer对象。
小技巧:如果想要按字符长度降序排列,那么可以在比较长度的时候,两个对象换换位置即可。像这样:
int num = new Integer(s2.length()).compareTo(s1.length());
if(num==0){num = s2.compareTo(s1);}
package fighting;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo3 {
/**
* 本实例实现按字符串长度输出字符串。
*
* 由于默认的是按自然顺序输出,而不是按长度输出,
* 即具备的比较性不是所需要的情况。这时要用到比较器
* 注意:主要条件相等,要判断次要条件
*/
public static void main(String[] args) {
TreeSet ts = new TreeSet(new Comparator(){
public int compare(Object o1,Object o2){
String s1 = (String)o1;
String s2= (String)o2;
int num = new Integer(s1.length()).compareTo(s2.length());
//长度相等,要判断字符串内容是否相同
if(num==0){
num = s1.compareTo(s2);
}
return num;
}
});
ts.add("aaaaa");
ts.add("bbbbbbbbbbbb");
ts.add("c");
ts.add("eee");
ts.add("ddd");
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
运行结果:
c
ddd
eee
aaaaa
bbbbbbbbbbbb
总结:TreeSet里存储对象,为了保证可比性,有两种方法:
一,元素自己实现Comparable接口,重写compareTo方法;
二,传递比较器给集合对象,比较器实现Comparator接口,重写compare方法。