博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

TreeSet的两种排序方式,含Comparable、Comparator

Posted on 2018-09-07 10:52  激流勇进、  阅读(1309)  评论(0编辑  收藏  举报

1.排序的引入

由于TreeSet可以实现对元素按照某种规则进行排序,例如下面的例子

 

 1 public class TreeSetDemo {
 2     public static void main(String[] args) {
 3         // 创建集合对象
 4         // 自然顺序进行排序
 5         TreeSet<Integer> ts = new TreeSet<Integer>();
 6  
 7         // 创建元素并添加
 8         // 20,18,23,22,17,24,19,18,24
 9         ts.add(20);
10         ts.add(18);
11         ts.add(23);
12         ts.add(22);
13         ts.add(17);
14         ts.add(24);
15         ts.add(19);
16         ts.add(18);
17         ts.add(24);
18  
19         // 遍历
20         for (Integer i : ts) {
21             System.out.println(i);
22         }
23     }
24 }

 运行结果为:

但是对自定义对象呢?

 1 public class TreeSetDemo02 {
 2     public static void main(String[] args) {
 3         TreeSet<Student> ts=new TreeSet<Student>();        
 4         //创建元素对象
 5         Student s1=new Student("zhangsan",20);
 6         Student s2=new Student("lis",22);
 7         Student s3=new Student("wangwu",24);
 8         Student s4=new Student("chenliu",26);
 9         Student s5=new Student("zhangsan",22);
10         Student s6=new Student("qianqi",24);
11         
12         //将元素对象添加到集合对象中
13         ts.add(s1);
14         ts.add(s2);
15         ts.add(s3);
16         ts.add(s4);
17         ts.add(s5);
18         ts.add(s6);
19         
20         //遍历
21         for(Student s:ts){
22             System.out.println(s.getName()+"-----------"+s.getAge());
23         }
24     }
25 }



 Student类:

 1 public class Student {
 2     private String name;
 3     private int age;
 4     
 5     public Student() {
 6         super();
 7         // TODO Auto-generated constructor stub
 8     }    
 9  
10     public Student(String name, int age) {
11         super();
12         this.name = name;
13         this.age = age;
14     }
15  
16     public String getName() {
17         return name;
18     }
19  
20     public void setName(String name) {
21         this.name = name;
22     }
23  
24     public int getAge() {
25         return age;
26     }
27  
28     public void setAge(int age) {
29         this.age = age;
30     }
31 }

运行结果:

原因分析:
由于不知道该安照那一中排序方式排序,所以会报错。
 
解决方法:
   1.自然排序
2.比较器排序

2.自然排序

自然排序要进行一下操作:
 
1.Student类中实现  Comparable<T>接口
2.重写Comparable接口中的Compareto方法
int compareTo(T o)
          比较此对象与指定对象的顺序。

故Student类为:特别注意在重写Compareto方法时,注意排序 

 1 package xfcy_04;
 2 /**
 3  * Student类
 4  * @author 晓风残月
 5  *
 6  */
 7 public class Student implements Comparable<Student> {
 8     private String name;
 9     private int age;
10     
11     public Student() {
12         super();
13         // TODO Auto-generated constructor stub
14     }    
15  
16     public Student(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21  
22     public String getName() {
23         return name;
24     }
25  
26     public void setName(String name) {
27         this.name = name;
28     }
29  
30     public int getAge() {
31         return age;
32     }
33  
34     public void setAge(int age) {
35         this.age = age;
36     }
37  
38     @Override
39     public int compareTo(Student s) {
40         //return -1; //-1表示放在红黑树的左边,即逆序输出
41         //return 1;  //1表示放在红黑树的右边,即顺序输出
42         //return o;  //表示元素相同,仅存放第一个元素
43         //主要条件 姓名的长度,如果姓名长度小的就放在左子树,否则放在右子树
44         int num=this.name.length()-s.name.length();  
45         //姓名的长度相同,不代表内容相同,如果按字典顺序此 String 对象位于参数字符串之前,则比较结果为一个负整数。
46         //如果按字典顺序此 String 对象位于参数字符串之后,则比较结果为一个正整数。
47         //如果这两个字符串相等,则结果为 0
48         int num1=num==0?this.name.compareTo(s.name):num;
49         //姓名的长度和内容相同,不代表年龄相同,所以还要判断年龄
50         int num2=num1==0?this.age-s.age:num1;
51         return num2;
52     }
53     
54 }

而主类中为:

 1 package xfcy_04;
 2  
 3 import java.util.TreeSet;
 4  
 5 /*
 6 * TreeSet存储自定义对象并保证排序和唯一。
 7  * 
 8  * 需求:请按照姓名的长度排序
 9  */
10 public class TreeSetDemo02 {
11     public static void main(String[] args) {
12         //创建集合对象        
13         TreeSet<Student> ts=new TreeSet<Student>();
14  
15         
16         //创建元素对象
17         Student s1=new Student("zhangsan",20);
18         Student s2=new Student("lis",22);
19         Student s3=new Student("wangwu",24);
20         Student s4=new Student("chenliu",26);
21         Student s5=new Student("zhangsan",22);
22         Student s6=new Student("qianqi",24);
23         
24         //将元素对象添加到集合对象中
25         ts.add(s1);
26         ts.add(s2);
27         ts.add(s3);
28         ts.add(s4);
29         ts.add(s5);
30         ts.add(s6);
31         
32         //遍历
33         for(Student s:ts){
34             System.out.println(s.getName()+"-----------"+s.getAge());
35         }
36     }
37 }

运行结果:

3、比较器排序

比较器排序步骤:
1.单独创建一个比较类,这里以MyComparator为例,并且要让其继承Comparator<T>接口
2.重写Comparator接口中的Compare方法
 
3.在主类中使用下面的 构造方法
 
TreeSet(Comparator<? superE> comparator) 
          构造一个新的空 TreeSet,它根据指定比较器进行排序。
 
 
主类:
 1 package xfcy_04;
 2  
 3 import java.util.TreeSet;
 4  
 5 /*
 6 * TreeSet存储自定义对象并保证排序和唯一。
 7  * 
 8  * 需求:请按照姓名的长度排序
 9  */
10 public class TreeSetDemo02 {
11     public static void main(String[] args) {
12         //创建集合对象
13         //TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
14         TreeSet<Student> ts=new TreeSet<Student>(new MyComparator());
15  
16         //创建元素对象
17         Student s1=new Student("zhangsan",20);
18         Student s2=new Student("lis",22);
19         Student s3=new Student("wangwu",24);
20         Student s4=new Student("chenliu",26);
21         Student s5=new Student("zhangsan",22);
22         Student s6=new Student("qianqi",24);
23         
24         //将元素对象添加到集合对象中
25         ts.add(s1);
26         ts.add(s2);
27         ts.add(s3);
28         ts.add(s4);
29         ts.add(s5);
30         ts.add(s6);
31         
32         //遍历
33         for(Student s:ts){
34             System.out.println(s.getName()+"-----------"+s.getAge());
35         }
36     }
37 }

MyComparator类:

 1 package xfcy_04;
 2  
 3 import java.util.Comparator;
 4  
 5 public class MyComparator implements Comparator<Student>{
 6  
 7     @Override
 8     public int compare(Student s1,Student s2) {
 9         // 姓名长度
10         int num = s1.getName().length() - s2.getName().length();
11         // 姓名内容
12         int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
13         // 年龄
14         int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
15         return num3;
16     }
17     
18     
19     
20     
21 }

学生类(不需要继承Comparetable接口)

 1 package xfcy_04;
 2 /**
 3  * Student类
 4  * @author 晓风残月
 5  *
 6  */
 7 public class Student{
 8     private String name;
 9     private int age;
10     
11     public Student() {
12         super();
13         // TODO Auto-generated constructor stub
14     }    
15  
16     public Student(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21  
22     public String getName() {
23         return name;
24     }
25  
26     public void setName(String name) {
27         this.name = name;
28     }
29  
30     public int getAge() {
31         return age;
32     }
33  
34     public void setAge(int age) {
35         this.age = age;
36     }
37     
38 }

运行结果:

4.比较器修改(代码精简)

由于单独创建一个类不是特别好,因而可以将MyComparetor的内容直接写到主类中

 1 public class TreeSetDemo {
 2         public static void main(String[] args) {
 3                 // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
 4         // 而匿名内部类就可以实现这个东西
 5         TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
 6             @Override
 7             public int compare(Student s1, Student s2) {
 8                 // 姓名长度
 9                 int num = s1.getName().length() - s2.getName().length();
10                 // 姓名内容
11                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
12                         : num;
13                 // 年龄
14                 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
15                 return num3;
16             }
17         });
18  
19         // 创建元素
20         Student s1 = new Student("linqingxia", 27);
21         Student s2 = new Student("zhangguorong", 29);
22         Student s3 = new Student("wanglihong", 23);
23         Student s4 = new Student("linqingxia", 27);
24         Student s5 = new Student("liushishi", 22);
25         Student s6 = new Student("wuqilong", 40);
26         Student s7 = new Student("fengqingy", 22);
27         Student s8 = new Student("linqingxia", 29);
28  
29         // 添加元素
30         ts.add(s1);
31         ts.add(s2);
32         ts.add(s3);
33         ts.add(s4);
34         ts.add(s5);
35         ts.add(s6);
36         ts.add(s7);
37         ts.add(s8);
38  
39         // 遍历
40         for (Student s : ts) {
41             System.out.println(s.getName() + "---" + s.getAge());
42         }
43     }
44 }
运行结果也如同上面一样
 

5.总结

A:自然排序:要在自定义类中实现Comparerable<T>接口  ,并且重写compareTo方法
B:比较器排序:在自定义类中实现Comparetor<t>接口,重写compare方法