`
SW_2011
  • 浏览: 7708 次
社区版块
存档分类
最新评论

PriorityQueu

    博客分类:
  • java
阅读更多

转自:http://blog.csdn.net/hudashi/article/details/6942789 PriorityQueu

 

 PriorityQueue

定义:

是个基于优先级堆的极大优先级队列。

此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序(参阅 Comparable),也可以根据 Comparator 来指定,这取决于使用哪种构造方法。

优先级队列不允许 null 元素。依靠自然排序的优先级队列还不允许插入不可比较的对象(这样做可能导致 ClassCastException)。

此队列的头是按指定排序方式的最小元素。如果多个元素都是最小值,则头是其中一个元素——选择方法是任意的。

 

队列的检索操作:

队列检索操作 poll、remove、peek 和 element 访问处于队列头的元素。

 

poll(): 获取并移除此队列的头,如果此队列为空,则返回 null

peek():获取但不移除此队列的头;如果此队列为空,则返回 null

remove(Object c):从此队列中移除指定元素的单个实例(如果存在)。

element:获取但不移除此队列的头。此方法与 peek 唯一的不同在于:此队列为空时将抛出一个异常。

除非队列为空,否则此实现返回 peek 的结果。

 

优先级队列是无界的,但是有一个内部容量,控制着用于存储队列元素的数组的大小。它总是至少与队列的大小相同。随着不断向优先级队列添加元素,其容量会自动增加。无需指定容量增加策略的细节。

 

注意1:该队列是用数组实现,但是数组大小可以动态增加,容量无限。

 

注意2:此实现不是同步的。不是线程安全的。如果多个线程中的任意线程从结构上修改了列表, 则这些线程不应同时访问 PriorityQueue 实例,这时请使用线程安全的PriorityBlockingQueue 类。

 

注意3:不允许使用 null 元素。

 

注意4:此实现为插入方法(offer、poll、remove() 和 add 方法)提供 O(log(n)) 时间; 为 remove(Object) 和 contains(Object) 方法提供线性时间; 为检索方法(peek、element 和 size)提供固定时间。

 

注意5:方法iterator()中提供的迭代器并不保证以有序的方式遍历优先级队列中的元素。至于原因可参考下面关于

PriorityQueue的内部实现如果需要按顺序遍历,请考虑使用 Arrays.sort(pq.toArray())。

 

注意6:可以在构造函数中指定如何排序。如: PriorityQueue() 使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。

       PriorityQueue(int initialCapacity)

使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。

      PriorityQueue(int initialCapacity, Comparator comparator)

使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器comparator来排序其元素。

 

注意7:此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。

 

PriorityQueue的内部实现浅析 :

 

PriorityQueue对元素采用的是堆排序头是按指定排序方式的最小元素。堆排序只能保证根是最大(最小),整个堆并不是有序的。方法iterator()中提供的迭代器可能只是对整个数组的依次遍历。也就只能保证数组的第一个元素是最小的。实例1的结果也正好与此相符。

public static void main(String[] args) { 
   PriorityQueue pq = new PriorityQueue(); 
     pq.add("dog"); 
     pq.add("apple");
     pq.add("fox");
     pq.add("easy"); 
     pq.add("boy"); 
while (!pq.isEmpty()) {
    System.out.print("left:"); 
    for (String s : pq) { 
         System.out.print(s + " "); } 
         System.out.println(); 
          System.out.println("poll(): " + pq.poll()); }
 } 

 

输出的结果如下:

left:apple boy fox easy dog//按照字母的asc||码排序
 poll(): apple 
left:boy dog fox easy
 poll(): boy 
left:dog easy fox
 poll(): dog
 left:easy fox 
poll(): easy 
left:fox 
poll(): fox 

 

 

可以看到,虽然PriorityQueue保持了队列顶部元素总是最小,但内部的其它元素的顺序却随着元素的减少始终处于变化之中。察看源代码来一探究竟。从Netbeans中非常方便的连接到PriorityQueue的add函数实现,最终跟踪到函数:

/**  
 * 添加元素后,重新调整堆的过程,这里从下向上调整x的位置。  
 * 这比初始构建堆更简单  
 */  
 
private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

 

相对于add的操作,该函数的入口参数k是指新加入元素的下标,而x 就是新加入的元素。

乍一看,这个函数的实现比较令人费解,尤其是parent的定义。通过进一步分析了解到,

 PriorityQueue内部成员数组 queue其实是实现了一个二叉树的数据结构,这棵二叉树的根节点是queue[0],左子节点是queue[1],右子节点是queue[2],而 queue[3]又是queue[1]的左子节点,依此类推,给定元素queue,该节点的父节点是queue[(i-1)/2]。因此 parent变量就是对应于下标为k的节点的父节点

 

弄清楚了这个用数组表示的二叉树,就可以理解上面的代码中while 循环进行的工作是,当欲加入的元素小于其父节点时,就将两个节点的位置交换。这个算法保证了如果只执行add操作,那么queue这个二叉树是有序的:该二叉树中的任意一个节点都小于以该节点为根节点的子数中的任意其它节点。这也就保证了queue[0],即队顶元素总是所有元素中最小的。

 

需要注意的是,这种算法无法保证不同子树上的两个节点之间的大小关系。举例来说,queue[3]一定会小于queue[7],但是未必会小于queue[9],因为queue[9]不在以queue[3]为根节点的子树上。

 

弄清楚了add的操作,那么当队列中的元素有变化的时候,对应的数组queue又该如何变化呢?察看函数poll():

//获取并移除根节点
public E poll() {
        if (size == 0)
            return null;
        int s = --size;//数组大小减一
        modCount++;
        E result = (E) queue[0];//获得根节点
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);//重新建堆,保证根节点为最小元素
        return result;
    }

 

/**  
 *  
 * 节点的调整:从此节点开始,由上至下进行位置调整。把小值上移。  
 * 可以称之为一次筛选,从一个无序序列构建堆的过程就是一个不断筛选的过程.  
 * 直到筛选到的节点为叶子节点,或其左右子树均大于此节点就停止筛选。  
 */  

private void siftDown(int k, E x) {
        if (comparator != null)
            siftDownUsingComparator(k, x);
        else
            siftDownComparable(k, x);
    }

 

/**  
 * 比较器为空的一趟筛选过程。  
 * PS:元素必须自己已经实现了Comparable方法  
 * 否则将抛出异常  
 */   

private void siftDownUsingComparator(int k, E x) {
        int half = size >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                comparator.compare((E) c, (E) queue[right]) > 0)
                c = queue[child = right];
            if (comparator.compare(x, (E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = x;
    }

  再比如remove()函数,去除指定元素后剩下的元素该如何变化?跟踪源码得到:

private E removeAt(int i) {
        assert i >= 0 && i < size;
        modCount++;
        int s = --size;
        if (s == i) // removed last element
            queue[i] = null;
        else {
            E moved = (E) queue[s];
            queue[s] = null;
            siftDown(i, moved);//剩下的元素重新建堆
            if (queue[i] == moved) {
                siftUp(i, moved);
                if (queue[i] != moved)
                    return moved;
            }
        }
        return null;
    }

 

这个函数的实现方法是,将队尾元素取出,插入到位置i,替代被删除的元素,然后做相应的调整,保证二叉树的有序,即任意节点都是以它为根节点的子树中的最小节点。进一步的代码就留给有兴趣的读者自行分析,要说明的是,对于 queue这样的二叉树结构有一个特性,即如果数组的长度为length,那么所有下标大于length/2的节点都是叶子节点,其它的节点都有子节点。

 

总结:可以看到这种算法的实现,充分利用了树结构在搜索操作时的优势,效率又高于维护一个全部有序的队列

分享到:
评论

相关推荐

    priorityQueue优先队列

    优先队列的实现,简单实用,实现一个按ttl时间优先的优先队列

    Java优先队列的实现

    数据结构与算法第六章,优先队列,heap_maximum 返回优先队列的最大值 heap_extract_max 删除并返回最大值 max_heap_insert插入值为key的元素进优先队列中 。

    2层设计-2.4G RF高频信号收发模块硬件(cadence原理图+PADS PCB图+BOM)文件.zip

    2层设计-2.4G RF高频信号收发模块硬件(cadence原理图+PADS PCB图+BOM)文件,可供学习及设计参考。

    JAVA文件传输(lw+源代码).zip

    FTP(File Transfer Protocol)是文件传输协议的简称。 FTP的主要作用,就是让用户连接上一个远程计算机(这些计算机上运行着FTP服务器程序)查看远程计算机有哪些文件,然后把文件从远程计算机上拷到本地计算机,或把本地计算机的文件送到远程计算机去。 目前FTP服务器软件都为国外作品,例如Server_U、IIS,国内成熟的FTP服务器软件很少,有一些如(Crob FTP Server),但从功能上看来远不能和那些流行的服务器软件媲美。

    语音端点检测及其在Matlab中的实现.zip

    语音端点检测及其在Matlab中的实现.zip

    Matlab 交互式多模型目标跟踪IMM.zip

    Matlab 交互式多模型目标跟踪IMM.zip

    numpy试题(2021年整理精品文档).zip

    numpynumpy试题(2021年整理精品文档).zip

    基于Python+Django城市PM2.5空气质量数据可视化分析系统

    【作品名称】:基于Python+Django城市PM2.5空气质量数据可视化分析系统 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】: Python基于Django城市PM2.5空气质量数据可视化分析 开发软件:Pycharm + Python3.7 + Django + Echarts + Mysql 实现目标:利用已经收集各个城市包括北京、上海、广州、成都、沈阳的PM2.5空气数据,利用python进行各种数据分析,将分析结果保存到csv文件中,然后利用django框架的网站,前端采用echart对分析的结果进行图表可视化展示。

    c#实现求解白拉修斯方程。程序使用文件流,四阶龙哥库塔法.zip

    c#实现求解白拉修斯方程。程序使用文件流,四阶龙哥库塔法

    单片机3.DSN

    单片机3.DSN

    NumPy 的用途是什么

    NumPy 的用途是什么

    Java游戏设计打飞机程序(源代码+LW).zip

    Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)Java游戏设计打飞机程序(源代码+LW)

    Java项目之企业人事工资管理系统(源码)

    Java项目之企业人事工资管理系统(源码) 开发语言:Java 框架:ssm 技术:JSP JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9

    vb.net做的教务管理系统 功能完善 后台数据库使用的acce.zip

    vb.net做的教务管理系统 功能完善 后台数据库使用的acce.zip

    Nvidia 17.1 for win10&Win11 vGPU驱动

    Nvidia 17.1最新win10&Win11 vGPU驱动 名称:551.78_grid_win10_win11_server2022_dch_64bit_internationa

    基于物品的协同过滤推荐调用实例(C#版).zip

    协同过滤算法(Collaborative Filtering)是一种经典的推荐算法,其基本原理是“协同大家的反馈、评价和意见,一起对海量的信息进行过滤,从中筛选出用户可能感兴趣的信息”。它主要依赖于用户和物品之间的行为关系进行推荐。 协同过滤算法主要分为两类: 基于物品的协同过滤算法:给用户推荐与他之前喜欢的物品相似的物品。 基于用户的协同过滤算法:给用户推荐与他兴趣相似的用户喜欢的物品。 协同过滤算法的优点包括: 无需事先对商品或用户进行分类或标注,适用于各种类型的数据。 算法简单易懂,容易实现和部署。 推荐结果准确性较高,能够为用户提供个性化的推荐服务。 然而,协同过滤算法也存在一些缺点: 对数据量和数据质量要求较高,需要大量的历史数据和较高的数据质量。 容易受到“冷启动”问题的影响,即对新用户或新商品的推荐效果较差。 存在“同质化”问题,即推荐结果容易出现重复或相似的情况。 协同过滤算法在多个场景中有广泛的应用,如电商推荐系统、社交网络推荐和视频推荐系统等。在这些场景中,协同过滤算法可以根据用户的历史行为数据,推荐与用户兴趣相似的商品、用户或内容,从而提高用户的购买转化率、活跃度和社交体验。 未来,协同过滤算法的发展方向可能是结合其他推荐算法形成混合推荐系统,以充分发挥各算法的优势。

    (文章复现)工业园区需求响应资源聚合优化配置方法matlab代码

    参考文献: [1]李明轩,齐步洋,贺大玮.工业园区需求响应资源聚合优化配置方法[J].电网技术,2022,46(09):3543-3549.DOI:10.13335/j.1000-3673.pst.2021.1666. 1.摘要 需求响应资源数量的不断提升对响应资源的优化运行方法提出了更高的要求。面向工业园区内负荷聚合商开展日内需求响应的应用场景,提出了一种资源聚合优化配置方法,即在日前时段对响应资源预先聚合优化形成一定数量满足 特定条件的聚合体,再在日内运行时段对各聚合体进行优化调用以满足电网侧需求。该方法实现对数量庞大、分散存在、特性各异的资源的灵活聚合和优化配置,充分发挥各资源响应潜力和互补特性,并通过将大量求解计算从日内转移至日前时段,平衡了响应实时性要求与计算规模的矛盾。通过算例分析验证了所提模型与方法的合理性和有效性。

    毕业设计[主机域名]HostDirector v1.01_hostdirector101.zip

    毕业设计[主机域名]HostDirector v1.01_hostdirector101.zip

    基于MATLAB的pca人脸识别.zip

    基于MATLAB的pca人脸识别.zip

    Qt+OpenCV通用视觉框架全套源码.zip.008

    Qt+OpenCV通用视觉框架全套源码.zip.008

Global site tag (gtag.js) - Google Analytics