zoukankan      html  css  js  c++  java
  • TreeSet集合

    TreeSet集合


    1、TreeSet集合底层实际上是一个TreeMapTreeMap底层是一个二叉树。放到TreeSet集合中的元素等同于放到TreeMap集合的key部分了。

    2、TreeSet集合中元素:无序不可重复,但是可以按照元素的大小顺序自动排序(按照添加对象的指定属性进行排序),称为可排序集合。添加的是同类对象时才会排序。

    排序的两种方法式:自然排序(实现Comparable)和 定制排序(Comparator)。

    TreeSet比较两个对象是否相同的标准为:compareTo()返回 0,不再是equals()

    3、TreeSet集合用处:编写程序从数据当中取出数据,在页面展示用户信息的时候按照生日升序或者降序,这个时候可以使用TreeSet集合,因为TreeSet集合放进去,拿出来就是有顺序的。

    //创建一个TreeSet集合
    TreeSet<String> ts=new TreeSet<>();
    //添加String
    ts.add("zhangsan");
    ts.add("lisi");
    ts.add("wangwu");
    ts.add("wangliu");
    ts.add("zhangsi");
    //遍历
    for(String s:ts){
        //按字典升序排序
        System.out.println(s);
    }
    

    结果: lisi wangliu wangwu zhangsan zhangsi

    对自定义类型放入TreeSet集合中会排序吗?

    class Person{
        int age;
        public Person(int age){
            this.age=age;
        }
        //重写toString()方法
        public String toString(){
            return "Person[age="+age+"]";
        }
    }
    
    //自定义类型放入TreeSet集合中会排序吗?
    Person p1=new Person(32);
    Person p2=new Person(20);
    Person p3=new Person(25);
    TreeSet<Person> persons=new TreeSet<>();
    persons.add(p1);
    persons.add(p2);
    persons.add(p3);
    //遍历
    for(Person p:persons){
        System.out.println(p);
    }
    

    报错:Person cannot be cast(转换) to class java.lang.Comparable

    TreeMap集合的put()添加元素的方法,当key==null(加入的key值部分为空)时:

    retern t.setValue(value);此时新的key值对应的value值直接将旧key值对应的value值覆盖了,不用调用equals方法判断key值是否相等。

    排序的实现:新加入的key值与集合中已经存在的key值用Comparable进行比较。

    报错原因分析:由于Preson类中没有实现java.lang.ComparablecompareTo()比较方法,所以加入的新值无法和集合中的值进行比较,从而无法实现排序。

    class Person implements Comparable<Preson>{
        int age;
        public Person(int age){
            this.age=age;
        }
        //重写compareTo()方法
        public int compareTo(Person p){
            /*p1.compareTo(p2): this就是p1,p就是p2*/
          /*  int age1=this.age;
             int age2=p.age;
            if(age1==age2){
                return 0;
            }else if(age1>age2){
                return 1;
            }else{
                return -1;
            }
            */
            return this.age-p.age; //此时是升序排序
        }
        
        //重写toString()方法
        public String toString(){
            return "Person[age="+age+"]";
        }
    }
    
    //自定义类型放入TreeSet集合中会排序吗?
    Person p1=new Person(32);
    Person p2=new Person(20);
    Person p3=new Person(25);
    TreeSet<Person> persons=new TreeSet<>();
    persons.add(p1);
    persons.add(p2);
    persons.add(p3);
    //遍历
    for(Person p:persons){
        System.out.println(p);
    }
    

    先按照年龄升序,如果年龄相同时按名字排序。

    class Person implements Comparable<Preson>{
        int age;
        String name;
        //构造方法省略
        public String toString(){
            return "Person{"+"name'"+name+"\'"+",age="+age+'}';
        }
        public int compareTo(Person p){
            if(this.age==p.age){
                //年龄相同时按照名字排序,String类型重写了compareTo()方法
               return  this.name.compareTo(p.name);
            }else{
                return this.age-p.age;
            }
        }
    }
    
        //当类中实现没有泛型时:
        public class User implements Comparable{}
        //compareTo()的第二种写法:
        public int compareTo(Object o){
            if(o instanceof User){//判断对象是否属于相同类型
                User user=(User)o;
                //从大到小排序(默认是从小到大排)
                return -this.name.compareTo(user.name);
                int compare = -this.name.compareTo(user.name);
                if(compare != 0){      //compare=0:表示两个对象相等
                    return compare;    //当两个对象名字不同时用名字比较大小
                }else{ //当两个对象名字相同时用年龄比较大小
                    return Integer.compare(this.age,user.age);
                }
            }else{
            	throw new RuntimeException("输入的类型不匹配");
            }
        }
        
    

    compareTo()方法的返回值很重要:

    返回0表示相同,value 会覆盖;返回>0,会继续在右子树上找(5-3=2>0,说明左边这个数字比较大,所以在右子树上找);返回 <0,会继续在左子树上找。

    4、TreeSet/TreeMap是自平衡二叉树,遵循左小右大原则存放,每次加入新数据都要从根节点开始从上往下进行比较,小的存放在左子树,大的存放在右子树。

    遍历二叉树的方式有前序遍历:根左右;中序遍历:左根右;后序遍历:左右根 ,TreeSet/TreeMap 集合采用的是中序遍历Iterator迭代器采用的是中序遍历。

    5、TreeSet集合中元素的第二种排序方式:使用比较器的方式。

    class WuGui{
        int age;
        
        public WuGui(int age){
            this.age=age;
        }
        public String toString(){
            return "小乌龟["+"age"+age+']';
        }
    }
    //单独编写一个比较器实现java.util.Comparator接口(Comparable是java.lang包下的)
    class WuGuiComparator implements Comparator<WuGui>{
        public int compare(WuGui w1,WuGui w2){
        //指定按照年龄排序
            return w1.age-w2.age;
        }
    }
    public static void main(String[] args){
        //创建TreeSet集合的时候,需要使用这个比较器
        /*
        TreeSet<WuGui> wuGui=new TreeSet<>();
        这样创建对象没有通过构造方法传递一个比较器进去
        */
        //给构造方法传递一个比较器
        TreeSet<WuGui> wuGui=new TreeSet<>(new WuGuiComparator());
        wuGuis.add(new WuGui(1000));
        wuGuis.add(new WuGui(800));
        wuGuis.add(new WuGui(810));
        for(WuGui wuGui:wuGuis){
            System.out.println(wuGui);
        }
        //编写一个比较器的第二种方法:匿名内部类(这个类没有名字,直接new接口),这样可以不用创建类
        TreeSet<WuGui> wuGui=new TreeSet<>(new Comparator<WuGui>(){
            public int compare(WuGui w1,WuGui w2){
                return w1.age-w2.age;
            }
        });
    }
    
      //当类中实现没有泛型时:
        public class User implements Comparator{ }
    public void test(){
        Comparator com = new Comparator(){
            //按照年龄从小到大排序
            public int compare(Object o1,Object o2){
                if(o1 instanceof User && o2 instanceof User){ //判断比较的两个对象类型是否相同
                    User u1 = (User)o1;
                    User u2 = (User)o2;
                    return Integer.compare(u1.getAge(),u2.getAge()); //根据年龄大小进行排序
                }else {
                    throw new RuntimeException("输入的数据类型不匹配");
                }
            }
        };
        //当传入参数时使用比较器comparator进行定制排序
        TreeSet set = new TreeSet(com);
        set.add(new User(Tom,12));
        //当两个对象的年龄相同时,会将其中第一个出现的存入集合中
        set.add(new User(Jerry,32));
        set.add(new User(Jim,32));
        //遍历
        Iterator iterator = set.iterator();
        while(iterator.hashNext()){
            System.out.println(iterator.next());
        }
    }
    
    

    TreeSet的有参构造方法:

    比较器赋值给了comparator

    此时调用put方法比较时comparator不为空

    image-20200707174854177

    最终结论:放到TreeSet或者TreeMap集合key部分的元素要想做到排序,有两种方式:一、放在集合中的元素实现java.util.Comparable接口。二、在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。

    ComparableComparator怎么选择?

    答:当比较规则不会发生改变时(比如String,Integer等实现了comparable接口比较规则无法改变),或者比较规则只有一个的时候,建议实现Comparator接口。当比较规则有多个,并且需要多个比较规则之间频繁切换时,建议使用Comparator接口。

    HashSetTreeSet里存放数据实际上是存放到了HashMapTreeMapkey部分。

    欢迎转载学习,只需注明文章出处即可(https://www.cnblogs.com/gyunf/) ,谢谢!
  • 相关阅读:
    BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
    BZOJ1305 [CQOI2009]dance跳舞 【网络流】
    BZOJ1452 [JSOI2009]Count 【树套树 (树状数组)】
    BZOJ1103 [POI2007]大都市meg 【树剖】
    BZOJ1927 [Sdoi2010]星际竞速 【费用流】
    POJ3450 Corporate Identity 【后缀数组】
    POJ3623 Best Cow Line, Gold 【后缀数组】
    POJ3415 Common Substrings 【后缀数组 + 单调栈】
    关于线上bug
    关于线上bug
  • 原文地址:https://www.cnblogs.com/gyunf/p/13343202.html
Copyright © 2011-2022 走看看