本文内容介绍大纲
上节课我们讲了优先级队列,优先级队列在插入元素时有个要求:
插入的元素不能是null或者元素之间必须要能够进行比较,为了简单起见,我们只是插入了Integer类型,那优先级队列中能否插入自定义类型对象呢?
我们先不用优先级队列来比较,先来看自定义类型如何进行比较…
我们写了一个 Student 的一个类,类内部有姓名和年龄两个属性,我们直接通过数组类进行比较…
我们来看结果
那么我们一个自定义类型中有两个属性甚至多个属性的情况下,如何进行比较呢?
首先在 自定义类后面 实现 Comparable 接口,然后重写 compareTo 方法.
在定义类时,实现Comparble接口即可,然后在类中重写compareTo方法。
在这里 重写的compareTo 方法里 ,以年龄为基准进行排序
现在我们再来运行
这种比较方法有一个缺点:
需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于内部顺序. 我们只能通过 compareTo 里的规则进行排序.
1.用户自定义比较器类,实现Comparator接口 2.覆写Comparator中的compare方法
我们来写一个 年龄的比较器
在数组排序时,我们可以将比较器作为参数,进行比较
我们来看运行结果:
这种比较的方法我非常推荐,因为 对内部类不影响,我们只是建立了一个外部的比较器 ,当比较时 ,我们可以将比较器作为参数进行排序的.
上节课我们学习了堆,这里我们就来看看 当自定义类的数据如何放入堆中.
集合框架中的PriorityQueue底层使用堆结构,因此其内部的元素必须要能够比大小,PriorityQueue采用了:
Comparble和Comparator两种方式。
1. Comparble是默认的内部比较方式,如果用户插入自定义类型对象时,该类对象必须要实现Comparble接口,并覆写compareTo方法 2. 用户也可以选择使用比较器对象,如果用户插入自定义类型对象时,必须要提供一个比较器类,让该类实现Comparator接口并覆写compare方法。
我们可以在构造 PriorityQueue 时,直接将比较器 作为参数 比较.
我们来看结果:
PriorityQueue 构造方法
我们要在下列数组中找到 最小的三个数据
int 8 arr = { 9,4,6,2,3,8,1,7 } ;
建立一个 K=3 的 大堆,依次遍历,比堆顶元素 小的入队,堆顶元素出队.
建立一个 K=3 的大堆
我们直接在 内部实现一个 comparator 的方法,o2 - o1是建立大堆,o1 - o2 是建立小堆.
TOPK 问题的思路我们在上一篇文章已经说的很清楚了,不明白的同学可以看一下 我的优先级队列的那一篇博客~~
完整代码展示:
运行结果:
运行成功,答案也正确了~~
好了,之前铺垫了那么多,我们给大家来两道练习题:
leetcode 题目链接——查找和最小的 K 对数字
思路:
本题使用topk的经典解法。利用优先级队列PriorityQueue,构造大小为K的大根堆。
1、堆没有放满的情况下,直接往堆里面添加,直到添加到K的大小。 2、堆的大小等于K之后,每次存放数对的时候,和堆顶比较,如果堆顶的元素大于当前的数对,那么出队。然后添加当前数对。 3、直到遍历完两个数组。
注意点:
1、 遍历两个数组的时候,大小要和k取最小值。防止超出 时间限制,爆内存,给我们两个长度都很大的数组,要求取前10个最大的数,我们光是遍历完这两个数组都会超出时间限制,因为这两个数组是升序的,所以我们不必完全遍历,取 arr.length 与 K 的最小值同样能达到效果. 2、取结果的时候注意,一定要判断队列此时空不空,队列虽然大小是k,但是有可能放不满k个。
完整代码展示:
运行结果:
leetcode 题目链接——最后一块石头的重量
题目描述
思路:
将所有石头的重量放入最大堆中。每次依次从队列中取出最重的两块石头 a 和b,必有 a ≥ b 。 如果 a > b,则将新石头a−b 放回到最大堆中; 如果a = b,两块石头完全被粉碎,因此不会产生新的石头。重复上述操作,直到剩下的石头少于 2 块。 最终可能剩下 1 块石头,该石头的重量即为最大堆中剩下的元素,返回该元素;也可能没有石头剩下,此时最大堆为空,返回 0。
代码展示:
好了今天的知识就分享到这里,希望大家多多练习,熟练掌握,感谢大家的欣赏与关注!!
谢谢欣赏!