PriorityQueue底层是用堆实现的,但相对于堆,PriorityQueue的删除操作并没有和堆的删除一致,堆是logN,PriorityQueue是用 for 循环实现的,堆可以查找和修改,PriorityQueue不可以
关于compare(int a, int b)方法需要先明确的两个关键点
- 在compare方法实现的源码中实际上是定义了如果如果调用compare方法大于0,则交换a b顺序。
- 如果我们想排序的是一个数组array,数组元素赋值给形参的传入顺序必定是 a = array[i - 1], b = array[i] 这样的顺序。
下面进入compare的用法详细说明了,我们先假设实际上 a 是大于 b 的,两个数的目前在数组中顺序即 a b
- 如果定义排序标准为 return a - b,则调用compare方法会返回正数,那就要交换 a 和 b ,输出顺序就变为 b a 了,即升序排列。
- 如果调用定义排序标准为 return b - a,则调用 b - a 时会返回负数,则程序不会执行交换操作,输出仍旧是 a b 顺序,即降序排列。
用堆来构造 PriorityQueue 的详细说明
PriorityQueue 是一种基于堆结构来实现优先队列功能的接口,可以用最大堆来实现,也可以用最小堆来实现
那如何判断我们所建立的 PriorityQueue 是用最大堆还是用最小堆来实现的呢?
比较容易判断的方法就是通过观察Comparator 比较器来判断,如果比较器定义的是 return o1 - o2 则是最小堆;如果比较器定义的是 return o2 - o1 则是最大堆;
具体原因如下:
- 当比较器定义的是 return o1 - o2 时,即对当前数组进行升序排列来构成堆,根据堆的构成原理,堆的根结点是在数组下标最小的位置,如果是升序排列,则将数组构造成一个堆后,根结点存储的是数组中最小的元素,也就是说我们构造了最小堆。
- 反之,如果比较器定义的是 return o2 - o1 ,就变成了对当前数组降序排列,根结点存储的是数组中最大的元素,也就是说我们构造了最大堆。
java Queue中 add/offer,element/peek,remove/poll中的三个方法均为重复的方法,在选择使用时不免有所疑惑,这里简单区别一下:
1、add()和offer()区别:
add()和offer()都是向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false。因此就可以在程序中进行有效的判断!PriorityQueue是一个无界队列,所以 add 和 offer 方法一样,add 底层调用的 offer方法
2、poll()和remove()区别:
remove() 和 poll() 方法都是从队列中删除第一个元素。如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常,但是新的 poll() 方法在用空集合调用时只是返回 null。因此新的方法更适合容易出现异常条件的情况。
3、element() 和 peek() 区别:
element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。
下面是Java中Queue的一些常用方法:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素