java中比较器Comparator的使用(结合PriorityQueue)

上期我们简单的介绍了下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的介绍到此就暂告一段落了,若文中有描述不当之处,希望大家多多指出,我们一起学习一起进步。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值