当前位置:首页 > 英文周记 > 正文内容

priorityqueue「priorityqueue自定义排序」

更新时间:2026-07-18 17:46:12 周记网3年前 (2023-04-15)英文周记86

PriorityQueue队列的使用

典型的生产消费者模型都存在队列的概念,在python语言中,提供了queue标准库,该库包含了Queue、FIFO和PriorityQueue三种类型的队列。

优先级处理的对列使用PriorityQueue,使用方法和Queue类似,区别在于放入队列的数据会进行排序,优先级高的数据会优先取出。

priorityqueue「priorityqueue自定义排序」

其中,priority为优先级字段,类型为int,数字越小,优先级越高;item为数据字段,可为任意类型。

put数据为数据类构造。

输出结果为:

从结果可以看到优先级为0的数据最先取出。

优先队列(PriorityQueue)

在数据结构中,普通的队列是先进先出,但有时我们可能并不想有这么固定的规矩,我们希望能有一个带优先级的队列。考虑在现实生活中,一些服务排队窗口会写着“军人依法优先”;送进医院的患者,即便是按顺序到达的,生病更加严重的往往优先级也会更高;还有操作系统中的作业调度也和优先级有关......

于是我们能不能改进队列?使得队列是有一定优先级的,这样能让一些事物和任务的处理变的更加灵活。当然是可以的,最基本的我们可以基于线性结构来实现,考虑基于线性结构的时间复杂度:

1、队列是一种FIFO(First-In-First-Out)先进先出的数据结构,对应于生活中的排队的场景,排在前面的人总是先通过,依次进行。

2、优先队列是特殊的队列,从“优先”一词,可看出有“插队现象”。比如在火车站排队进站时,就会有些比较急的人来插队,他们就在前面先通过验票。优先队列至少含有两种操作的数据结构:insert(插入),即将元素插入到优先队列中(入队);以及deleteMin(删除最小者),它的作用是找出、删除优先队列中的最小的元素(出队)。

结构\操作 入队 出队

普通线性结构 O(1) O(n)

顺序线性结构 O(n) O(1)

普通线性结构实现的优先队列出队时间复杂度是O(n),因为出队要拿出最优先的元素,也就是相对最大的元素(注意:大小是相对的,我们可以指定比较规则),从而要扫描一遍整个数组选出最大的取出才行。而对于顺序线性结构的入队操作,入队后可能破坏了原来的有序性,从而要调整当前顺序。

可以看到使用线性结构总有时间复杂度是O(n)的操作,还有没有更好的实现方式呢,当然是有的,这就要来聊一聊堆Heap。

堆严格意义上来说又叫二叉堆(Binary Heap),因为它的结构是一颗完全二叉树,堆一般分为最大堆和最小堆。

堆性质:

结构性:堆是一颗除底层外被完全填满的二叉树,底层的节点从左到右填入,这样的树叫做完全二叉树。即缺失结点的部分一定再树的右下侧。

堆序性:由于我们想很快找出最小元,则最小元应该在根上,任意节点都小于它的后裔,这就是小顶堆(Min-Heap);如果是查找最大元,则最大元应该在根上,任意节点都要大于它的后裔,这就是大顶堆(Max-heap)。

最大堆:父亲节点的值大于孩子节点的值

最小堆:父亲节点的值小于孩子节点的值

由于是完全二叉树,节点的索引之间有着一定的关系,故我们可以使用数组来存储二叉堆,具体如下:

如果从索引为0开始存储,则父亲和孩子节点的索引关系如下:

当我们需要向一个最大堆添加一条新的数据时,此时我们的堆变成了这样。

此时,由于新数据的加入已经不符合最大堆的定义了。所以我们需要对新加入的数据进行shift up操作,将它放到它应该在的位置。shift up操作时我们将新加入的数据与它的父节点进行比较。如果比它的父节点大,则交换二者。

此时我们就完成了 对新加入元素的shift up操作。

当我们从堆中(也就是优先队列中)取出一个元素时。我们是将堆顶的元素弹出。(只能从堆顶取出)

此时这个堆没有顶了,那么该怎么办呢?我们只需要把这个堆最后一个元素放到堆顶就可以了。

此时我们就完成了弹出一个元素之后的shift down操作。

replace:去除最大元素后,放入一个新元素

实现:可以先extractMax,再add,两次longn操作。

实现:将堆顶的元素替换以后sift down,一次O(logn)操作

将n个元素逐个插入到一个空堆中,算法复杂度是O(nlogn),heapify的过程,算法的复杂度为O(n).

heapify:将任意数组整理成堆的形状。

首先将一个数组抽象成一个堆。这个过程,我们称之为heapify。

之后我们找到这个堆中第一个非叶子节点,这个节点的位置始终是数组的数量除以2,也就是索引5位置的27,从这个节点开始,对每一个非叶子的节点,,进行shift down操作。

27比它的子节点51要小,所以交换二者。

接下来我们看索引2位置的20。首先呢,我们需要将20与它两个子节点中较大的51交换。

每个节点堆化的时间复杂度是O(logn),那 个节点的堆化的总时间复杂度是O(nlogn)。

推导过程

堆化节点从倒数第二层开始。堆化过程中,需要比较和交换的节点个数与这个节点的高度k成正比。

所以 heapify() 时间复杂度是 O(n).

建堆后,数组中的数据是大顶堆。把堆顶元素,即最大元素,跟最后一个元素交换,那最大元素就放到了下标为n的位置。

这个过程有点类似上面的“删除堆顶元素”的操作,当堆顶元素移除之后,把下标n的元素放堆顶,然后再通过堆化的方法,将剩下的n-1个元素重新构建成堆。一直重复这个过程,直到最后堆中只剩下下标为1的元素,排序就完成了。

topk和selectk问题既可以使用快排思想解决,也可以使用优先队列解决。

快排:O(n) 空间O(1)

优先队列:O(nlogk) 空间O(k)

优先队列的有i是,不需要一次性知道所有数据,数据流的方式处理。

java priorityqueue 哪些方法

1.下表显示了jdk1.5中的阻塞队列的操作:

add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常

remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常

element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常

offer 添加一个元素并返回true 如果队列已满,则返回false

poll 移除并返问队列头部的元素 如果队列为空,则返回null

peek 返回队列头部的元素 如果队列为空,则返回null

put 添加一个元素 如果队列满,则阻塞

take 移除并返回队列头部的元素 如果队列为空,则阻塞

remove、element、offer 、poll、peek 其实是属于Queue接口。

2.阻塞队列的操作可以根据它们的响应方式分为以下三类:aad、removee和element操作在你试图为一个已满的队列增加元素或从空队列取得元素时 抛出异常。当然,在多线程程序中,队列在任何时间都可能变成满的或空的,所以你可能想使用offer、poll、peek方法。这些方法在无法完成任务时 只是给出一个出错示而不会抛出异常。

注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的。

3.还有带超时的offer和poll方法变种,例如,下面的调用:

boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);

尝试在100毫秒内向队列尾部插入一个元素。如果成功,立即返回true;否则,当到达超时进,返回false。同样地,调用:

Object head = q.poll(100, TimeUnit.MILLISECONDS);

如果在100毫秒内成功地移除了队列头元素,则立即返回头元素;否则在到达超时时,返回null。

4.最后,我们有阻塞操作put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。

java.ulil.concurrent包提供了阻塞队列的4个变种。默认情况下,LinkedBlockingQueue的容量是没有上限的(说的不准确,在不指定时容量为Integer.MAX_VALUE,不要然的话在put时怎么会受阻呢),但是也可以选择指定其最大容量,它是基于链表的队列,此队列按 FIFO(先进先出)排序元素。

ArrayBlockingQueue在构造时需要指定容量, 并可以选择是否需要公平性,如果公平参数被设置true,等待时间最长的线程会优先得到处理(其实就是通过将ReentrantLock设置为true来 达到这种公平性的:即等待时间最长的线程会先操作)。通常,公平性会使你在性能上付出代价,只有在的确非常需要的时候再使用它。它是基于数组的阻塞循环队 列,此队列按 FIFO(先进先出)原则对元素进行排序。

PriorityBlockingQueue是一个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是**的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元 素要具有比较能力。

介绍一下PriorityQueue,以及优先队列实现大小根堆

PriorityQueue优先队列

import java.util.PriorityQueue;它是java.util包下的

我们利用优先队列可以实现从小到大的排序,那么其实也就相当于可以实现一个特殊的小根堆和一个特殊的大根堆.

因为从小到大排序的数组必然是小根堆,从大到小排序的数组必然是大根堆.

但是小根堆未必是从小到大排序的数组,大根堆未必是从大到小排序的数组.

java的 的priorityqueue 默认是最小堆吗

默认是最小堆。可以自己设置一个比较器转变为最大堆

   // 如果不是整数就自己修改比较处的代码即可

   PriorityQueue pq = new PriorityQueue(new Comparator() {

       @Override               

       public int compare(Object o1, Object o2) {

           if ((Integer) o1 = (Integer) o2) {

               return 1;

           } else {

               return -1;

           }

       }

   );

标签: priorityqueue

“priorityqueue「priorityqueue自定义排序」” 的相关文章

priorityqueue「PriorityQueue排序规则」

priorityqueue「PriorityQueue排序规则」

java priorityqueue 哪些方法 1.下表显示了jdk1.5中的阻塞队列的操作:add 增加一个元索 如果队列已满,则抛出一个III...

priorityqueue「c++队列priorityqueue」

priorityqueue「c++队列priorityqueue」

优先队列(PriorityQueue) 在数据结构中,普通的队列是先进先出,但有时我们可能并不想有这么固定的规矩,我们希望能有一个带优先级的队列。考虑在现实生活中,一些服务排队窗口会写着“军人依法优...

priorityqueue「priorityqueue用法 java」

priorityqueue「priorityqueue用法 java」

java priorityqueue 哪些方法 1.下表显示了jdk1.5中的阻塞队列的操作:add 增加一个元索 如果队列已满,则抛出一个III...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。