TreeSet是一个具有唯一元素的二叉树集合,同时TreeSet是Set接口的一个实现类(TreeSet实现了Set的接口),它具有Set的特点。
Set的特点有:不可重复,元素无顺序,没有带索引的方法(因此不能使用普通for循环来遍历,也不能通过索引来获取或删除Set集合中的元素值)。
TreeSet的特点:不可重复,没有带索引的方法(因此不能使用普通for循环来遍历,也不能通过索引来获取或删除TreeSet集合中的元素值),可以将元素按自定义规则进行排序。
接下来我们将从TreeSet的三个特点并结合代码来学习TreeSet。(由于TreeSet没有带索引的方法,因此TreeSet的第二个特点只能使用forEach语句与Iterator迭代器来实现TreeSet的遍历)
注意:TreeSet的默认数据类型是Object类,理论上我们可以通过add()方法来添加任意数据类型,但是如果我们这样子做,当我们进行遍历输出的时候就会遇到麻烦!!!因此我们在使用TreeSet的时候,请使用泛型来约束数据类型!!!
一、不可重复
数据类型为String类型的TreeSet,用普通输出语句来实现TreeSet元素的输出
public class Demo01 {
public static void main(String[] args) {
//若要使用TreeSet,我们需要导入import java.util.TreeSet;
//我们使用泛型来约束TreeSet的数据类型为String类型
TreeSet<String> set=new TreeSet<>();
//使用add()方法来添加数据
set.add("aa");
set.add("aa");
set.add("bb");
//打印
System.out.println(set);
}
}
运行结果(重复的aa元素被筛掉)
Integer类型的TreeSet,用普通输出语句来实现TreeSet元素的输出
public class Demo01 {
public static void main(String[] args) {
//若要使用TreeSet,我们需要导入import java.util.TreeSet;
//我们使用泛型来约束TreeSet的数据类型为Integer数据类型
TreeSet<Integer> set=new TreeSet<>();
//使用add()方法来添加数据
set.add(18);
set.add(20);
set.add(20);
//打印
System.out.println(set);
}
}
运行结果(重复的20元素被筛掉,TreeSet不可重复特点)
TreeSet操作自定义Student类型数据
Student类
//若要在TreeSet中遍历我们自定义的数据类,我们需要复写Comparable接口中的compareTo()方法
public class Student implements Comparable<Student>{
private String name;
private char gender;
private int age;
private double salary;
//无参构造方法
public Student() {}
//全参构造方法
public Student(String name, char gender, int age, double salary) {
this.name = name;
this.gender = gender;
this.age = age;
this.salary = salary;
}
//Set,Get方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//toString方法
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gender=" + gender +
", age=" + age +
", salary=" + salary +
'}';
}
//复写compareTo方法
@Override
public int compareTo(Student o) {
return -1;
//return的值不同,输出的结果就不同
//若返回的结果是0,则只会返回第一个元素
//若返回的结果是1,则会返回所有元素(按输入的顺序输出)
//若返回的结果是-1,则会返回所有元素(按输入的顺序反向输出)
}
}
Student类型的TreeSet,用forEach语句来实现TreeSet元素的遍历输出
public class Demo01 {
public static void main(String[] args) {
//若要使用TreeSet,我们需要导入import java.util.TreeSet;
//我们使用泛型来约束TreeSet的数据类型为Student类型
TreeSet<Student> set=new TreeSet<>();
//使用add()方法来添加数据
set.add(new Student("zhangsan",'男',18,2500.00));
set.add(new Student("lisi",'女',19,2600.00));
set.add(new Student("wangwu",'男',20,3000.00));
set.add(new Student("wangwu",'男',20,3000.00));
//在此我们使用forEach来遍历TreeSet
//Student是set的数据类型,我们将set的数据存入student(此名字你可以自定义)中并输出
for(Student student:set){
System.out.println(student);
}
}
}
Student类 return 0的输出
Student类 return 1的输出
我们发现这里输出的内容含有重复的值,其实这并没有违反TreeSet不可重复这一条件,这是因为我们实际上并没有真正重写Comparable接口中的compareTo()方法,在元素进行比较的时候,计算机并没有通过比较他们的值来判定他们是否不同,而是通过比较他们存储的内存地址来比较他们是否不同,而我们都知道在我们存储数据时,都会为元素开辟一个内存空间,而开辟的内存空间各个内存空间的地址肯定是不同的,因此计算机认为他们是不同的。
Student类 return -1的输出
我们发现这里输出的内容含有重复的值,其实这并没有违反TreeSet不可重复这一条件,这是因为我们实际上并没有真正重写Comparable接口中的compareTo()方法,在元素进行比较的时候,计算机并没有通过比较他们的值来判定他们是否不同,而是通过比较他们存储的内存地址来比较他们是否不同,而我们都知道在我们存储数据时,都会为元素开辟一个内存空间,而开辟的内存空间各个内存空间的地址肯定是不同的,因此计算机认为他们是不同的。
那么我们如何使得TreeSet存储的数据的值不可重复呢?下面我们来复写Comparable接口中的compareTo()方法
二、元素可以按我们自定义规则进行排序
Student类重写compareTo()方法(使用年龄排序,相同年龄不会存储,在这里我们规定数据按年龄进行排序,那么就相当于告诉计算机即使数据名字不同,年龄相同就认为它们就是相同的)
//复写compareTo方法,按年龄进行排序
@Override
public int compareTo(Student o) {
//这里我们根据年龄来排序,当我们存入一个数据后,它就变成了this,之后我们再存入数据,此数据就是o
//例如我们刚开始存入(zhangsan,18),那么此时this.age=18,之后我们存入(lisi,19),那么o.getAge()=19
//所以此时result=18-19=-1<0,表明传入对象(o)年龄>this对象年龄,传入对象存入右边即(zhangsan,18),(lisi,19)
//之后我们又传入(wangwu,20),那么它会先于(zhangsan,18)比较,再与(lisi,19)比较,最后形成(zhangsan,18),(lisi,19),(wangwu,20)
//最后我们传入(chenliu,20),那么它会先于(zhangsan,18)比较,再与(lisi,19)比较,最后再与(wangwu,20)比较,result=18-18=0,年龄相同,计算机认为它们是重复的,不在存入
int result=this.age-o.getAge();
return result;
}
Student类型的TreeSet,用forEach语句来实现TreeSet元素的遍历输出
public class Demo01 {
public static void main(String[] args) {
//若要使用TreeSet,我们需要导入import java.util.TreeSet;
//我们使用泛型来约束TreeSet的数据类型为Student类型
TreeSet<Student> set=new TreeSet<>();
//使用add()方法来添加数据
set.add(new Student("zhangsan",'男',18,2500.00));
set.add(new Student("lisi",'女',19,2600.00));
set.add(new Student("wangwu",'男',20,3000.00));
set.add(new Student("chenliu",'男',20,3000.00));
//在此我们使用forEach来遍历TreeSet
//Student是set的数据类型,我们将set的数据存入student(此名字你可以自定义)中并输出
for(Student student:set){
System.out.println(student);
}
}
}
运行结果:(可以看到wangwu与chenliu名字不同,但是年龄相同,计算机也会认为他们重复)
Student类重写compareTo()方法(使用年龄与姓名进行排序,相同年龄,排名字,名字与年龄若均相同,计算机则会认为数据重复)
//复写compareTo方法
@Override
public int compareTo(Student o) {
//这里我们先根据年龄来排序,当我们存入一个数据后,它就变成了this,之后我们再存入数据,此数据就是o
//例如我们刚开始存入(zhangsan,18),那么此时this.age=18,之后我们存入(lisi,19),那么o.getAge()=19
//所以此时result=18-19=-1<0,表明传入数据>当前数据,传入元素存入右边即(zhangsan,18),(lisi,19)
//之后我们又传入(wangwu,20),那么它会先于(zhangsan,18)比较,再与(lisi,19)比较,最后形成(zhangsan,18),(lisi,19),(wangwu,20)
//最后我们传入(chenliu,20),那么它会先于(zhangsan,18)比较,再与(lisi,19)比较,最后再与(wangwu,20)比较,年龄相同,对名字进行排序
int result=this.age-o.getAge();
//下面的语句指出,如果result==0(即年龄相同),则执行this.name.compareTo(o.getName())对名字进行排序,否则(年龄不同)执行result(按年龄排序),并将最终结果存储在变量中。
//那么这样wangwu与chenliu的年龄相同时,会比较他们的姓名,名字不同,因此计算机会将它们视为不同对象,并根据它们的姓名进行排序
result = result==0 ? this.name.compareTo(o.getName()) :result;
return result;
}
Student类型的TreeSet,用forEach语句来实现TreeSet元素的遍历输出
public class Demo01 {
public static void main(String[] args) {
//若要使用TreeSet,我们需要导入import java.util.TreeSet;
//我们使用泛型来约束TreeSet的数据类型为Student类型
TreeSet<Student> set=new TreeSet<>();
//使用add()方法来添加数据
set.add(new Student("zhangsan",'男',18,2500.00));
set.add(new Student("lisi",'女',19,2600.00));
set.add(new Student("wangwu",'男',20,3000.00));
set.add(new Student("chenliu",'男',20,3000.00));
//在此我们使用forEach来遍历TreeSet
//Student是set的数据类型,我们将set的数据存入student(此名字你可以自定义)中并输出
for(Student student:set){
System.out.println(student);
}
}
}
运行结果:(可以看到wangwu与chenliu均输出)
三、使用Iterator迭代器来实现TreeSet元素遍历输出
public class Demo01 {
public static void main(String[] args) {
//若要使用TreeSet,我们需要导入import java.util.TreeSet;
//我们使用泛型来约束TreeSet的数据类型为String类型
TreeSet<String> set=new TreeSet<>();
//使用add()方法来添加数据
set.add("aa");
set.add("aa");
set.add("bb");
//在此我们使用Iterator迭代器来遍历TreeSet
//创建迭代器对象
Iterator<String> iterator=set.iterator();
//判断该位置是否有值,iterator.hasNext()它会查看我们当前位置是否存在元素,存在元素返回true,不存在元素返回false
while(iterator.hasNext()){
//获取该位置的元素值,iterator.next()它会取得我们目前位置的元素,然后指针后移
System.out.println(iterator.next());
}
}
}
运行结果:(不可重复)
OK! TreeSet的这三大特点的运用就介绍完毕!