TreeSet

TreeSet是Set接口的另一个实现类,它内部采用自平衡的排序二叉树来存储元素,这样的结构可以保证TreeSet集合中没有重复的元素,并且可以对元素进行排序。

package com.first;

import java.util.TreeSet;

public class HelloWorld {
    public static void main(String[] args) {
        TreeSet<Integer> ts=new TreeSet<>();
        ts.add(3);
        ts.add(2);
        ts.add(2);
        ts.add(3);
        ts.add(1);
        System.out.println(ts);
    }
}

运行结果为

[1, 2, 3]

TreeSet存储自定义对象

package com.first;

import java.util.TreeSet;

public class HelloWorld {
    public static void main(String[] args) {
        TreeSet<Person> ts=new TreeSet<>();
        ts.add(new Person("张三",23));
        ts.add(new Person("李四",13));
        ts.add(new Person("王五",43));
        ts.add(new Person("赵六",33));
        System.out.println(ts);
    }
}



class Person{
    String name;
    int age;

    public Person(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;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }

}

运行结果为

Exception in thread "main" java.lang.ClassCastException: com.first.Person cannot be cast to java.lang.Comparable
    at java.util.TreeMap.compare(TreeMap.java:1188)
    at java.util.TreeMap.put(TreeMap.java:531)
    at java.util.TreeSet.add(TreeSet.java:255)
    at com.first.HelloWorld.main(HelloWorld.java:8)

报了类型转换异常的错误,无法转换成Comparable。要进行排序,需要告诉程序根据什么规则进行排序。Person类需要实现Comparable这个接口,并重写里边的compareTo方法。

class Person implements Comparable<Person>{

    //省略的代码同上
    @Override
    public int compareTo(Person p) {

        return 0;
    }

}

运行结果为

[Person [name=张三, age=23]]

这里写图片描述
add张三的时候,会将其作为树根。add李四的时候会调用compareTo方法,返回值为0,就会认为李四和张三是一样的,然后就不存了,后面的依次类推。

改为return 1;,运行结果为

[Person [name=张三, age=23], Person [name=李四, age=13], Person [name=王五, age=43], Person [name=赵六, age=33]]

这里写图片描述
add张三的时候,会将其作为树根。add李四的时候会调用compareTo方法,返回值为正数,然后存到右边。add王五的时候也会调用compareTo方法,先和张三比,返回正数,放到李四的右边,再和李四比,也是返回正数,放到李四的右边。赵六同上。取的时候按照中序遍历的顺序取。

改为return -1;,运行结果为

[Person [name=赵六, age=33], Person [name=王五, age=43], Person [name=李四, age=13], Person [name=张三, age=23]]

这里写图片描述
这次返回值为负数,将李四放到张三的左边。

在TreeSet集合如何存储元素取决于compareTo方法的返回值

  • 返回0,先看有没有,没有就存上,有的话就不存了
  • 返回负数,会存在左边(可以理解为新加的元素比原有元素小,放到其左边)
  • 返回正数,会存在右边(可以理解为新加的元素比原有元素大,放到其右边)
  • 取的时候通过中序遍历取(可以理解为从小到大取)

新需求:按照年龄来排序

将comparTo方法改为

@Override
public int compareTo(Person p) {

    return this.age-p.age;
}

运行结果为

[Person [name=李四, age=13], Person [name=张三, age=23], Person [name=赵六, age=33], Person [name=王五, age=43]]

这里写图片描述
add张三,将其作为根元素。add李四,李四会调用compareTo方法,13-23=-10,是一个负数,放到张三的左边。add王五,放到右边。add赵六,先和张三比,33-23=10,为正数,放到右边,再和王五比,33-43=-10,为负数,放到王五的左边。取的时候按照中序遍历取。

第二种比较的方法,指定比较器。

有时候,定义的类没有实现Comparable接口或者实现了Comparable接口而不想按照定义的compareTo()方法进行排序。例如,希望字符串可以按照长度来进行排序,这时可以通过自定义比较器的方式对TreeSet集合中的元素排序。

package com.first;

import java.util.TreeSet;

public class HelloWorld {
    public static void main(String[] args) {
        TreeSet<String> ts=new TreeSet<String>();
        ts.add("aaaaaa");
        ts.add("z");
        ts.add("wc");
        ts.add("bdc");
        ts.add("b");
        System.out.println(ts);
    }
}

运行结果为

[aaaaaa, b, bdc, wc, z]

String类默认已经实现了Comparable接口,重写compareTo方法按字典顺序比较两个字符串。

现在我们想按照字符串的长度来进行排序

package com.first;

import java.util.Comparator;
import java.util.TreeSet;

public class HelloWorld {
    public static void main(String[] args) {
        TreeSet<String> ts = new TreeSet<String>(new CompareByLen());
        ts.add("aaaaaa");
        ts.add("z");
        ts.add("wc");
        ts.add("bdc");
        ts.add("b");
        System.out.println(ts);
    }
}

class CompareByLen implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) {
        int num = s1.length() - s2.length();
        return num==0?s1.compareTo(s2):num;//长度相同的话再比较一下内容
    }

}

运行结果为

[b, z, wc, bdc, aaaaaa]

总结

TreeSet是用来排序的

使用方法

  • 自然顺序(Comparable)
    • TreeSet的add方法会把存入的对象提升为Comparable类型
    • 调用对象的compareTo方法和集合中的对象比较
    • 根据compareTo方法返回的结果进行存储
  • 比较器顺序(Comparator)
    • 创建TreeSet的时候可以指定一个Comparator
    • 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的规则排序
    • add方法内部会自动调用Comparator接口中的compare方法排序
  • 两种方式的区别
    • TreeSet构造函数什么都不传,默认就按照类中Comparable的顺序(没有就报ClassCastException)
    • TreeSet如果传入了Comparator,就优先按照Comparator
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值