赞
踩
上期我们简单的介绍了下java中的排序接口Comparable的使用,由于Comparable是不够灵活的一种排序接口,它要去修改对象的类的代码。所以,我们今天介绍一款较为灵活的比较器接口Comparator。
首先,还是创建一个实体类Person2:
- public class Person2 {
- private int age;
- private String name;
- private int xuehao;
-
- public Person2() {
- }
-
- public Person2(int age, String name, int xuehao) {
- this.age = age;
- this.name = name;
- this.xuehao = xuehao;
- }
-
- public int getXuehao() {
- return xuehao;
- }
-
- public void setXuehao(int xuehao) {
- this.xuehao = xuehao;
- }
-
- 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 "Person2{" +
- "age=" + age +
- ", name='" + name + '\'' +
- ", xuehao=" + xuehao +
- '}';
- }
-
- }
然后在我们的创作一个测试类Mytest:
- public class Mytest {
- public static void main(String[] args) {
- Person2[] person2s = {new Person2(15,"张三",34),
- new Person2(5, "李四",12),
- new Person2(10, "王五",88)};
-
- //创建比较器对象cp
- Comparator<Person2> cp = new Comparator<Person2>() {
- @Override//重写compare方法,使按照xuehao升序
- //o2.getXuehao()-o1.getXuehao():按照xuehao降序
- public int compare(Person2 o1, Person2 o2) {
- return o1.getXuehao()-o2.getXuehao();
- }
- };
-
- System.out.println("排序前:");
- for(Person2 p:person2s){
- System.out.println(p.toString());
- }
- //对数组person2s安装比较器cp进行排序
- Arrays.sort(person2s, cp);
-
- System.out.println("排序后:");
- for(Person2 p:person2s){
- System.out.println(p.toString());
- }
- }
- }
运行结果如下:(按照xuehao升序)
- 排序前:
- Person2{age=15, name='张三', xuehao=34}
- Person2{age=5, name='李四', xuehao=12}
- Person2{age=10, name='王五', xuehao=88}
- 排序后:
- Person2{age=5, name='李四', xuehao=12}
- Person2{age=15, name='张三', xuehao=34}
- Person2{age=10, name='王五', xuehao=88}
当然,你也可以修改比较器中的compare方法,使其安装age降序,具体修改如下:
- //创建比较器对象cp
- Comparator<Person2> cp = new Comparator<Person2>() {
- @Override//重写compare方法,使按照age降序
- public int compare(Person2 o1, Person2 o2) {
- //若为o1.getAge()-o2.getAge():按照age升序
- return o2.getAge()-o1.getAge();
- }
- };
修改后,运行结果如下:
- 排序前:
- Person2{age=15, name='张三', xuehao=34}
- Person2{age=5, name='李四', xuehao=12}
- Person2{age=10, name='王五', xuehao=88}
- 排序后:
- Person2{age=15, name='张三', xuehao=34}
- Person2{age=10, name='王五', xuehao=88}
- Person2{age=5, name='李四', xuehao=12}
可以发现我们修改person2的排序方式并不用去修改person2中的代码,所以说Comparator比Comparable更加的灵活。
最后我们看下Comparator在优先队列中的使用,我们修改Mytest中的代码如下:
- public class Mytest {
- public static void main(String[] args) {
-
- //创建一个比较器
- Comparator<Person2> cp = new Comparator<Person2>() {
- @Override
- public int compare(Person2 o1, Person2 o2) {
- //安照年龄升序
- return o1.getAge()-o2.getAge();
- }
- };
-
- //将比较器cp作为参数创建一个优先队列
- PriorityQueue<Person2> priorityQueue = new PriorityQueue<>(cp);
- //往队列中加入数据
- priorityQueue.add(new Person2(15,"张三",2));
- priorityQueue.add(new Person2(33,"张三",78));
- priorityQueue.add(new Person2(1,"张三",33));
- priorityQueue.add(new Person2(5, "李四",14));
- priorityQueue.add(new Person2(55,"张三",35));
- priorityQueue.add(new Person2(10, "王五",22));
-
- System.out.println("遍历优先队列:");
- for(Person2 p:priorityQueue){
- System.out.println(p.toString());
- }
- System.out.println("依次弹出优先队列中的值");
- while(!priorityQueue.isEmpty()){
- System.out.println(priorityQueue.poll());
- }
-
- }
- }
运行结果如下:
- 遍历优先队列:
- Person2{age=1, name='张三', xuehao=33}
- Person2{age=5, name='李四', xuehao=14}
- Person2{age=10, name='王五', xuehao=22}
- Person2{age=33, name='张三', xuehao=78}
- Person2{age=55, name='张三', xuehao=35}
- Person2{age=15, name='张三', xuehao=2}
- 依次弹出优先队列中的值
- Person2{age=1, name='张三', xuehao=33}
- Person2{age=5, name='李四', xuehao=14}
- Person2{age=10, name='王五', xuehao=22}
- Person2{age=15, name='张三', xuehao=2}
- Person2{age=33, name='张三', xuehao=78}
- Person2{age=55, name='张三', xuehao=35}
显然,重结果中我们可以看出,优先队列弹出元素的顺序是按照age升序的。同时,细心的同学可以从我们的遍历结果中发现,优先队列中各个元素是按照其年龄(age)值来维护了一个完全二叉树的小顶堆,如下图所示:(节点中为各个元素age的值)
下面我们去修改比较器,具体代码如下:
- //创建一个比较器
- Comparator<Person2> cp = new Comparator<Person2>() {
- @Override
- public int compare(Person2 o1, Person2 o2) {
- //按照xuehao降序
- return o2.getXuehao()-o1.getXuehao();
- }
- };
然后再运行,得到如下结果:
- 遍历优先队列:
- Person2{age=33, name='张三', xuehao=78}
- Person2{age=55, name='张三', xuehao=35}
- Person2{age=1, name='张三', xuehao=33}
- Person2{age=15, name='张三', xuehao=2}
- Person2{age=5, name='李四', xuehao=14}
- Person2{age=10, name='王五', xuehao=22}
- 依次弹出优先队列中的值
- Person2{age=33, name='张三', xuehao=78}
- Person2{age=55, name='张三', xuehao=35}
- Person2{age=1, name='张三', xuehao=33}
- Person2{age=10, name='王五', xuehao=22}
- Person2{age=5, name='李四', xuehao=14}
- Person2{age=15, name='张三', xuehao=2}
此时我们可以发现我们元素的弹出顺序是按照xuehao降序的,而遍历的结果是按照xuehao来维护的一个大顶堆(如下图 )。
至此,我们可以总结为如下:
在优先队列中,如果定义的比较器是按照某值X升序(return o1.X-o2.X)排序的,那么优先队列中元素的位置会按照X的值所构建的小顶堆来放置;
在优先队列中,如果定义的比较器是按照某值X降序(return o2.X-o1.X)排序的,那么优先队列中元素的位置会按照X的值所构建的大顶堆来放置;
在使用比较器的时候,你也可以先创建一个比较器的类,然后在要使用的时候去new一个该类的对象也可以。比如在我们例子中,我们可以去创建下面这个类:
- public class MyComparator implements Comparator<Person2> {
- @Override
- public int compare(Person2 o1, Person2 o2) {
- //按照年龄age升序
- return o1.getAge()-o2.getAge();
- }
- }
然后在使用的时候直接去创建该类的对象,可以将我们的测试类的代码修改如下部分:
- //创建一个比较器
- // Comparator<Person2> cp = new Comparator<Person2>() {
- // @Override
- // public int compare(Person2 o1, Person2 o2) {
- // //按照xuehao降序
- // return o2.getXuehao()-o1.getXuehao();
- // }
- // };
- //此处比较器的排序规则要到MyComparator中去查看或修改
- MyComparator cp = new MyComparator();
比较器接口Comparator的介绍到此就暂告一段落了,若文中有描述不当之处,希望大家多多指出,我们一起学习一起进步。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。