TreeSet集合
目录
public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
-
元素有序,但这里的顺序不是元素的存储与取出顺序,而是按照一定规则进行的排序,具体排序方式取决于构造方法 :TreeSet() : 无参构造,根据其元素的自然排序进行排序
TreeSet(Comparator comparator) : 根据指定的比较器进行排序
-
没有带索引的方法,所以不能使用普通for循环
-
是Set集合,所以不包含重复元素
import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { TreeSet<Integer> ts = new TreeSet<Integer>(); //<>中不能为基本数据类型 ts.add(10); ts.add(40); ts.add(60); ts.add(20); ts.add(20); for(Integer i : ts){ System.out.println(i); } } } // 自然排序 10 20 40 60
自然排序:Comparable接口的使用
-
该接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的
compareTo
方法被称为其自然比较方法
只有唯一方法:
int compareTo(T o) 将此对象与指定的对象进行比较以进行排序。 返回一个负整数,零或正整数,因为该对象小于,等于或大于指定对象。
案例分析
问题
//学生类,没有实现Comparable接口 public class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public Student() { } 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; } }
//demo,运行会报错 //未覆盖java.lang.Comparable中的抽象方法compareTo(com.Set.TreeSetD.Student) import java.util.TreeSet; public class demo { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<Student>(); Student s1 = new Student("林青霞",33); Student s2 = new Student("张曼玉",23); Student s3 = new Student("眼红和",14); Student s4 = new Student("金城武",32); ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); for(Student s : ts){ System.out.println(s.getName()+","+s.getAge()); } } }
解决方法
-
让学生类实现Comparable接口
-
让学生类重写CompareTo方法
public class Student implements Comparable<Student>{ ... @Override public int compareTo(Student s) { return 0; } }
执行dome类结果是:
林青霞,33 //只有一个元素,原因是在重写后默认比较规则中,返回值是0,是0则认为添加来的元素跟比较的是一样的
返回值改为恒正数
再次重写
public class Student implements Comparable<Student>{ ... @Override public int compareTo(Student s) { return 1; } }
执行dome类结果是:
林青霞,33 张曼玉,23 眼红和,14 金城武,32 //跟存入顺序相同
返回值改为恒负数
再次重写
public class Student implements Comparable<Student>{ ... @Override public int compareTo(Student s) { return -1; } }
执行dome类结果是:
金城武,32 眼红和,14 张曼玉,23 林青霞,33 //跟存入顺序相反
按需求改写为 按年龄排序
再次重写
public class Student implements Comparable<Student>{ ... @Override public int compareTo(Student s) { return this.getAge()-s.getAge(); } }
执行dome类结果是:
眼红和,14 张曼玉,23 金城武,32 林青霞,33 //跟年龄大小顺序保持一致
bug
import java.util.TreeSet; public class demo { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<Student>(); Student s1 = new Student("林青霞",33); Student s2 = new Student("张曼玉",23); Student s3 = new Student("眼红和",14); Student s4 = new Student("金城武",32); Student s5 = new Student("胡一菲",32); ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); for(Student s : ts){ System.out.println(s.getName()+","+s.getAge()); } } } // Student s4 = new Student("金城武",32); Student s5 = new Student("胡一菲",32); 年龄相同则认为他们俩为同一个对象,就不存入此集合
解决办法:
@Override public int compareTo(Student s) { int num = this.age-s.age; int num2 = num == 0 ? this.name.compareTo(s.name):num; //String类可以直接使用该方法,因为String类实现了Comparable接口并且重写了该方法 return num2; }
执行dome类结果是:
眼红和,14 张曼玉,23 胡一菲,32 金城武,32 林青霞,33
总结
-
用TreeSet集合存储自定义对象,无参构造方法使用自然排序会报错
-
自然排序,就是让所属的类实现Comparable接口,重写CompareTo()方法
-
重写方法时,一定要注意排序规则必须按照要求的主要次要条件进行
比较器排序Comparator的使用
public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() { //匿名内部类 @Override public int compare(Student o1, Student o2) { //在Comparator中重写compare方法 int num = o1.getAge()- o2.getAge(); int num2 = num == 0 ? o1.getName().compareTo(o2.getName()):num; return num2; } }); Student s1 = new Student("林青霞",33); Student s2 = new Student("张曼玉",23); Student s3 = new Student("眼红和",14); Student s4 = new Student("金城武",32); Student s5 = new Student("胡一菲",32); ts.add(s1); ts.add(s2); ts.add(s3); ts.add(s4); ts.add(s5); for(Student s : ts){ System.out.println(s.getName()+","+s.getAge()); } } // 眼红和,14 张曼玉,23 胡一菲,32 金城武,32 林青霞,33
两种方法比较
自然排序 | 比较器排序 | |
---|---|---|
使用的接口或者类 | Comparable接口 | Comparator类(可实例化) |
使用方法 | 在TreeSet的无参构造中使用 | 在TreeSet的有参构造中使用(匿名内部类) |
重写的内容以及位置 | 在Student(元素类型类)中实现Comparable接口并重写CompareTo方法 | 直接在构造器的匿名内部类中重写Compare方法 |
使用TreeSet集合最需要注意的就是:
- 次要条件的分析