TreeSet用法详解

TreeSet 总结
特点:
     无序(指的时存储顺序和取出顺序不同),但是内部其实有集合本身的排序方式(注:但是,添加到TreeSet中的数据类型必须是相同的)
     唯一(无重复元素)

A:底层数据结构是红黑树(是一个自平衡的二叉树)

B:保证元素的排序方式
    a:自然排序(元素具备比较性)
        1)让元素所属的类实现Comparable接口
        2) 在类中重写Comparable的抽象方法compareTo()

    b:比较器排序(集合具备比较性)
        1) 让集合构造方法接收Comparator的实现类对象
        2) 在比较器中重写Comparator的抽象方法compare

       实质上,compareTo方法和compare方法内实体几乎相同

核心compareTo()或者compare()方法实体,决定了二叉平衡树的构建,也就决定了最终的排序方式
   
     函数返回值的三种情况
     return 0;  新添加的对象/数据 和当前“根”结点相等,表示已有该对象/数据,不添加
     return 1;  新添加的对象/数据 比当前“根”结点大,进入右孩子循环比较,直到插入,或者遇到相同的元素
     return -1; 新添加的对象/数据 比当前“根”结点小,进入左孩子循环比较,直到插入,或者遇到相同的元素

     输出的方式是二叉树的前序遍历


一般来说,类中需要实现comparable接口,同时重写compareTo方法,才能确定排序方式
但 String、Integer、Double 等类都已完成了上述功能,故可直接使用
TreeSet<String> ts=new TreeSet<String> ();

对于集合中的元素为自定义类对象,则一般来说有三种实现方式:

eg: TreeSet内部为Student对象
需求:按照学生的姓名长度 从短到长排序,姓名长度相同,按照年龄从大到小排序

1:自然排序
        1)让元素所属的类实现Comparable接口
        2) 在类中重写Comparable的抽象方法compareTo()
缺点:此类对象一旦在类中重写compateTo方法后, 只能有一种确定的排序方式
           
           public class Student implements Comparable<Student>{
               private String name;
               private int age;
               ...
 

            tags 1: 默认生成的compareTo方法如下:

               @Override
            public int compareTo(Student o) {
                return 0;         
            }
            这种情况下只能添加第一个元素,其他的元素全都被误判成和第一个元素“相等”,而未添加

            tags  2:
               @Override
            public int compareTo(Student o) {
                return 1;         
            }
            这种情况下不能判断是否是重复元素,即不能满足唯一性,且所有的结点全部依次插到右孩子上
            输出的顺序和添加的顺序恰好相同


            tags 3:
             @Override
            public int compareTo(Student o) {
                return -1;         
            }
            这种情况下不能判断是否是重复元素,既不能满足唯一性,且所有的结点全部依次插到左孩子上
            输出的顺序和添加的顺序相反

            tags 4: 根据具体需求写,注意排序的优先级,特别注意 考虑完优先级先后之后,要考虑元素是否完全相同
               @Override
               public int compareTo(Student s){
                   主要条件:按照姓名长度从小到大排序
                   int num1=(this.name.length()-s.getName().lenfth());
                   注意 这里的this实际上代表的是add方法添加进来的元素(向上转型成的类),s代表的是根结点
                如果改成按照姓名长度的 从长到短的顺序排序  则 num1=s.getName().lenfth()-this.name.length()

                次要条件:按照年龄从大到小的顺序排序
                int num2=(num1==0?(s.getAge()-this.age):num1);


                注意:如果两个学生的姓名长度相同、年龄相同,程序跑完上面得到的是num2=0,故一定要判断姓名是否相同
                      如果不判断,程序就会默认这两个元素完全相同(然而两者的姓名不一定相同),返回0,不添加
                      
                      注意:排序中比较字符串,要用compareTo() 方法,而不是equals()
                            前者返回的是int值(0,1,-1),后者返回的是 true /false
                 int num3=(num2==0?(this.name.compareTo(s.getName())): num2);
                  
                  return num3;

               }
           }

在类中实现Comparable接口后,创建对象
TreeSet<Student> ts=new TreeSet<Student>();
...

2:创建比较器类
    1)实现Comparator接口
    2)重写compare方法
优点: 能够通过创建不同的比较器类,就能实现不同的排序方式

    1)
    Student类正常实现

    2)
    构建自定义比较器类
    注意:使用到Comparator时,一定要导包

    import java.util.Comparator;
    public  class MyComparator implements Comparator<Student>{

        重写compare 方法 ,注意这里和compareTo的区别是 形参为2个,第一个相当于compareTo中的this
        @Override
        public int compare (Student s1,Student s2){
            内容和1中的compareTo基本一致,将this替换成s1
        }
    }

    3)main方法中
    导包
    import java.util.Comparator;
    创建对象
    TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
    ...


3:创建匿名对象类
    适用于一次或次数极少的情况下
    1)
    Student类正常实现

    2)在含main方法中
    匿名对象类:创建类 同时 继承一个父类或者实现一个接口

    TreeSet<Student> ts=new TreeSet<Student>(new Comparator<Student>{
        实现Comparator接口,要重写compare方法

        @Override
        public int compare(Student s1,Student s2){
            方法主体和2中一样
            ...
        }
    });

猜你喜欢

转载自blog.csdn.net/qq_2300688967/article/details/81154070