一、比较器
compareTo()方法
比较器进行比较的思路:将比较的数据作差,返回一个int类型的数据,a-b>0则a大于b,反之a<b或a=b。
下面采用这个思路对不同数据类型进行比较
1.比较基本数据类型
1)比较int类型数据
int i1=5;
int i2=6;
System.out.println(i1-i2);//-1
2)比较String类型数据
String类实现了Comparable接口,重写了compareTo()
//使用String类中的compareTo方法进行比较
String s1="abc";
String s2="abcd";
System.out.println(s1.compareTo(s2));//-1
3)比较Double类型数据
Double类实现了也Comparable接口,重写了compareTo()
//使用Double类中的compareTo方法进行比较
double d1=9.8;
double d2=9.1;
System.out.println(((Double) d1).compareTo((Double) d2));//1
2.比较自定义的数据类型
1)内部比较器:写在类的内部,实现Comparable接口,重写compareTo()方法
引用数据类型中的比较器是内部比较器
自定义一个Student2类型,实现Comparable接口,重写compareTo()方法
class Student2 implements Comparable<Student2>{
private int age;
private String name;
private double height;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public Student2(int age, String name, double height) {
this.age = age;
this.name = name;
this.height = height;
}
@Override
public String toString() {
return "Student2{" +
"age=" + age +
", name='" + name + '\'' +
", height=" + height +
'}';
}
//内部比较器
//1.先让类实现Comparable接口 2.重写构造器方法(Alt+Insert)
@Override
public int compareTo(Student2 o) {
//return 0;
//自行定义需要比较的内容
/*//1.比较年龄
return this.getAge()-o.getAge();*/
/*//2.比较姓名
//这里的this.getName()调用的compareTo()方法是String类中的compareTo(),与当前类中重写的compareTo()无关
return this.getName().compareTo(o.getName());*/
//3.比较身高,同理(Double)this.getHeight()调用的compareTo()方法是Double类中的compareTo(),与当前类中重写的compareTo()无关
return ((Double)this.getHeight()).compareTo((Double)o.getHeight());
}
}
在main方法中调用该方法中重写的compareTo()
Student2 st1 = new Student2(25, "xiaoming", 170.9);
Student2 st2 = new Student2(22, "xiaohong", 160.4);
System.out.println(st1.compareTo(st2));
2)外部比较器:在类的外部重新定义一个类,专门用于比较,必须实现Comparator接口,重写compareTo()方法
在Student类的外面编写多个外部比较器,实现比较不同属性的功能或实现更复杂的功能
//外部比较器
class Bijiao1 implements Comparator<Student2>{
//外部比较器中可以只写compareTo()方法
@Override
public int compare(Student2 o1, Student2 o2) {
//return 0;
//比较年龄
return o1.getAge()-o2.getAge();
}
}
//可以编写多个比较器,对Student2中的不同属性进行比较
class Bijiao2 implements Comparator<Student2>{
@Override
public int compare(Student2 o1, Student2 o2) {
//return 0;
//比较姓名
return o1.getName().compareTo(o2.getName());
}
}
class Bijiao3 implements Comparator<Student2>{
@Override
public int compare(Student2 o1, Student2 o2) {
//return 0;
//比较身高
return ((Double) o1.getHeight()).compareTo((Double) o2.getHeight());
}
}
//外部比较器也可以实现更复杂的功能
class Bijiao4 implements Comparator<Student2>{
@Override
public int compare(Student2 o1, Student2 o2) {
//return 0;
//在年龄相等的情况下再比较身高,否则直接比较年龄
if ((o1.getAge()-o2.getAge())==0){
return ((Double) o1.getHeight()).compareTo((Double) o2.getHeight());
}else {
return o1.getAge()-o2.getAge();
}
}
}
在main方法中调用外部比较器
//调用外部比较器进行比较,因为有多个外部比较器,比较了不同的属性,所以可以需要比较哪个属性就调用哪个比较器
//获取外部比较器,使用接口指向实现类的方式
Comparator bj1 = new Bijiao1();
System.out.println(bj1.compare(st1, st2));
Comparator bj2 = new Bijiao2();
System.out.println(bj2.compare(st1, st2));
3.内部比较器与外部比较器的区别
1)内部比较器符合Java封装的思想,高内聚。我们自定义一个类时,可以使用内部比较器
2)外部比较器符合Java多态的思想,扩展性好。对于使用别人定义好的类时,可以使用外部比较器
3)平时对于代码中的需要比较多个属性或需要对多个属性进行多种排序(学生按照学号排序,姓名排序等),使用外部比较器。
二、TreeSet实现类
1.二叉树
二叉树是数据结构中的一种逻辑结构,它的物理结构是跳转结构
对于一组数据12,3,7,9,3,16,二叉树的存放顺序为
TreeSet中的底层原理是二叉树。
二叉树的遍历方式有三种
1)中序遍历:左 根 右(TreeSet)
2)先序遍历:根 左 右
3)后序遍历:左 右 根
例如上图,中序遍历的方式为:
先看最左,3,3的左边没有,看根,是3,于是列表放入[3],3的右边7,7左无,列表为[3,7],同样方式放入9[3,7,9],然后是12,12左遍历过了,放入[3,7,9,12],最后放入16。可以看到中序遍历的结果是升序
2.TreeSet的特点
唯一,无序(不会按照输入的顺序进行排列),有序(按照升序进行排列)
3.TreeSet的使用
1)存放Integer类型数据(int类型会自动装箱成为Integer类型)
//创建TreeSet,存放Integer类型数据
TreeSet<Integer> ts = new TreeSet<>();
ts.add(12);
ts.add(3);
ts.add(7);
ts.add(9);
ts.add(3);
ts.add(16);
System.out.println(ts.size());//唯一:5
System.out.println(ts); //按照升序排列[3, 7, 9, 12, 16]
2)存放String类型数据
//创建TreeSet,存放String类型数据
TreeSet<String> ts2 = new TreeSet<>();
ts2.add("axxx");
ts2.add("cxxx");
ts2.add("fxxx");
ts2.add("exxx");
ts2.add("dxxx");
ts2.add("cxxx");
System.out.println(ts2.size());//唯一:5
System.out.println(ts2); //按照升序排列[axxx, cxxx, dxxx, exxx, fxxx]
2)存放自定义类型数据
- 内部比较器
创建自定义的Student3类
class Student3 implements Comparable<Student3>{
private int age;
private String name;
public Student3(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student1{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Student3 o) {
//return 0;
//return this.getAge() - o.getAge();
return (o1.getName()).compareTo(o2.getName());
}
}
//创建TreeSet,存放自定义类型数据
//1.内部比较器
TreeSet<Student3> ts3 = new TreeSet<>();
ts3.add(new Student3(10, "elili"));
ts3.add(new Student3(8, "blili"));
ts3.add(new Student3(18, "glili"));
ts3.add(new Student3(22, "alili"));
ts3.add(new Student3(5, "clili"));
ts3.add(new Student3(8, "blili")); //重复不会录入
System.out.println(ts3.size());
System.out.println(ts3);
- 外部比较器
编写两个外部比较器
class Bijiao5 implements Comparator<Student3> {
@Override
public int compare(Student3 o1, Student3 o2) {
return o1.getAge()-o2.getAge();
}
}
class Bijiao6 implements Comparator<Student3> {
@Override
public int compare(Student3 o1, Student3 o2) {
return (o1.getName()).compareTo(o2.getName());
}
}
再先将代码中内部比较器的部分全部注释,再创建外部比较器对象,将外部比较器对象传入TreeSet
//2.外部比较器(先注释掉Student3、main方法的内部比较器部分代码)
//创建一个对象来接收外部比较器
Comparator<Student3> bj5 = new Bijiao5();
//将外部比较器的对象传入TreeSet
TreeSet<Student3> ts3 = new TreeSet<>(bj5);
ts3.add(new Student3(10, "elili"));
ts3.add(new Student3(8, "blili"));
ts3.add(new Student3(18, "glili"));
ts3.add(new Student3(22, "alili"));
ts3.add(new Student3(5, "clili"));
ts3.add(new Student3(8, "blili")); //重复不会录入
System.out.println(ts3.size());
System.out.println(ts3);
- 不使用内外部比较器的匿名内部类写法(面向对象)
//3.利用匿名内部类方式,Comparator接口不能直接创建对象,但是可以写成匿名内部类
Comparator<Student3> bj6 = new Comparator<Student3>() {
@Override
public int compare(Student3 o1, Student3 o2) {
//实现规则写在匿名内部类里
return (o1.getName()).compareTo(o2.getName());
}
};
//再将匿名内部类的对象传入TreeSet
TreeSet<Student3> ts4 = new TreeSet<>(bj6);
//4.也可以将匿名内部类的对象直接粘贴到bj6的位置
/*new Comparator<Student3>() {
@Override
public int compare(Student3 o1, Student3 o2) {
//实现规则写在匿名内部类里
return (o1.getName()).compareTo(o2.getName());
}
}*/
//上面这部分直接粘贴到TreeSet<Student3> ts4 = new TreeSet<>()的()中
TreeSet<Student3> ts5 = new TreeSet<>(new Comparator<Student3>() {
@Override
public int compare(Student3 o1, Student3 o2) {
//实现规则写在匿名内部类里
return (o1.getName()).compareTo(o2.getName());
}
});
}