许多应用程序都需要处理有序的元素,但不一定要求他们全部有序,或者是不一定要以此就将他们排序。很多情况下我们会手机一些元素,处理当前键值最大的元素,然后再收集更多的元素,再处理当前键值最大的元素。如此这般。

在这种情况下,一个合适的数据结构应该支持两种操作:删除最大元素和插入元素。这种数据类型叫做优先队列(priority queue)。优先队列的使用和队列(删除最老的元素)以及栈(删除最新的元素)类似,但高效地实现该数据结构有一定的困难。

下文将简单的讨论优先队列的基本表现形式(其一或者两种操作都能在线性时间完成)。

2.4.1 API

优先队列是一种抽象数据类型(是一种能够对使用者隐藏数据表示的数据类型),它表示了一组值和对这些值的操作,它的抽象层使我们能够方便地将应用程序和我们学习的各种具体实现隔离开来。优先队列最重要的操作就是删除最大元素和插入元素,所以我们会把精力集中在它们身上。删除最大元素的方法名为delMax(),插入元素的方法名为insert()。通过less()来比较两个元素。如果允许重复元素,最大表示的是所有最大元素之一。为了将API定义完整,我们还需要加入构造函数和一个空队列测试方法。为了保证灵活性,我们在实现中使用了泛型,将实现Comparable接口的数据的类型作为参数Key。这使得我们可以不必再区别元素和元素的键,对数据类型和算法的描述也将更加清晰和简洁。

  public class MaxPQ<Key extends Comparable<Key>>
MaxPQ() 
MaxPQ(int max)
MaxPQ(Key[] a) 
void  Insert(Key v)  
Key   max() 
Key   delMax()   
boolean   isEmpty()
int     size() 
 创建一个优先队列
 创建一个初始容量为max的优先队列
 用a[]中的元素创建一个优先队列
 向优先队列中插入一个元素
 返回最大元素
 删除最大元素
 返回队列是否为空
 返回优先队列中的元素个数

表2.4.1  泛型优先队列的API

为了用例代码的方便,API包含的三个构造函数使得用例可以构造指定大小的优先队列(还可以用给定的一个数组将其初始化)。为了使用例代码更加清晰,我们会在适当的地方使用另一个类MinPQ。它和MaxPQ类似,只是含有一个delMin()方法来删除并返回队列中键值最小的那个元素。MaxPQ的任意实现都能很容易地转化为MinPQ的实现,反之亦然,只需要改变一下less()比较的方向即可。

优先队列的调用示例

考虑一下问题:输入N个字符串,每个字符串都对映着一个整数,你的任务就是从中找出最大的(或是最小的)M个整数(及其最小的)M个整数(及其关联的字符串)。解决这个问题的一种方法是将输入排序然后从中找出M个最大元素,但输入会非常庞大。另一种方法是将每个新的输入和已知的M个最大元素比较,但除非M较小,否则这种比较的代价会非常昂贵。只要我们能够高效地实现insert()和delMin(),下面的优先队列用例中调用了MinPQ的TopM就能使用优先队列解决这个问题,这就是目标。

示例 时间 空间
排序算法的用例 NlogN
N
调用初级实现的优先队列 NM
M
调用基于堆排序的优先队列 NlogM
M

表2.4.2 N个输入中找到最大的M个元素成本

一个优先队列的用法


public class TopM {   

    // This class should not be instantiated.
private TopM() { } /**
* Reads a sequence of transactions from standard input; takes a
* command-line integer M; prints to standard output the M largest
* transactions in descending order.
*/
public static void main(String[] args) {
int M = Integer.parseInt(args[0]);
MinPQ<Transaction> pq = new MinPQ<Transaction>(M+1); while (StdIn.hasNextLine()) {
// Create an entry from the next line and put on the PQ.
String line = StdIn.readLine();
Transaction transaction = new Transaction(line);
pq.insert(transaction); // remove minimum if M+1 entries on the PQ
if (pq.size() > M)
pq.delMin();
} // top M entries are on the PQ // print entries on PQ in reverse order
Stack<Transaction> stack = new Stack<Transaction>();
for (Transaction transaction : pq)
stack.push(transaction);
for (Transaction transaction : stack)
StdOut.println(transaction);
}
}

从命令行输入一个整数M从输入流获得一系列字符串,输入流的每一行表示一个交易。这段代码调用了MinPQ并会打印数字最大的M行。它用到了Transaction类,构造了一个用数字作为键的优先队列。当优先队列的大小超过M时就删掉其中最小的元素。处理完所有交易,优先队列中存放着以曾旭排列的最大的M个交易,然后这段代码将他们放到一个栈中,遍历这个栈以点到他们的顺序,从而将他们按降序打印出来。


《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅰ的更多相关文章

  1. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅶ(延伸:堆排序的实现)

    2.4.5 堆排序 我们可以把任意优先队列变成一种排序方法.将所有元素插入一个查找最小元素的有限队列,然后再重复调用删除最小元素的操作来将他们按顺序删去.用无序数组实现的优先队列这么做相当于进行一次插 ...

  2. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅵ

    · 学后心得体会与部分习题实现 心得体会: 曾经只是了解了优先队列的基本性质,并会调用C++ STL库中的priority_queue以及 java.util.PriorityQueue<E&g ...

  3. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅴ

    命题Q.对于一个含有N个元素的基于堆叠优先队列,插入元素操作只需要不超过(lgN + 1)次比较,删除最大元素的操作需要不超过2lgN次比较. 证明.由命题P可知,两种操作都需要在根节点和堆底之间移动 ...

  4. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅳ

    2.4.4 堆的算法 我们用长度为 N + 1的私有数组pq[]来表示一个大小为N的堆,我们不会使用pq[0],堆元素放在pq[1]至pq[N]中.在排序算法中,我们只能通过私有辅助函数less()和 ...

  5. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅲ

    2.4.3 堆的定义 数据结构二叉堆能够很好地实现优先队列的基本操作.在二叉堆的数组中,每个元素都要保证大于等于另两个特定位置的元素.相应地,这些位置的元素又至少要大于等于数组中的两个元素,以此类推. ...

  6. 《Algorithms 4th Edition》读书笔记——2.4 优先队列(priority queue)-Ⅱ

    2.4.2初级实现 我们知道,基础数据结构是实现优先队列的起点.我们可以是使用有序或无序的数组或链表.在队列较小时,大量使用两种主要操作之一时,或是所操作元素的顺序已知时,它们十分有用.因为这些实现相 ...

  7. C++Primer 4th edition读书笔记-第二章

    1 变量的定义用于为变量分配存储空间,还可以为变量指定初始值.在一个程序中,变量有且只有一个定义.声明用于向程序表明变量的名字和类型.定义也是声明:当定义变量时,我们声明了它的类型和名字.可以通过使用 ...

  8. 《Algorithms 4th Edition》读书笔记——3.1 符号表(Elementary Symbol Tables)-Ⅳ

    3.1.4 无序链表中的顺序查找 符号表中使用的数据结构的一个简单选择是链表,每个结点存储一个键值对,如以下代码所示.get()的实现即为遍历链表,用equals()方法比较需被查找的键和每个节点中的 ...

  9. 《C++ Primer 4th》读书笔记 序

    注:本系列读书笔记是博主写作于两三年前的,所以是基于<C++ Primer>第四版的,目前该书已更新至第五版,第五版是基于C++11标准的,貌似更新挺多的.博主今年应届硕士毕业,如若过阵子 ...

随机推荐

  1. win7系统如何恢复administrator用户

    默认情况下,administrator用户是禁用的. 要恢复的话,右键单击我的电脑 管理-->本地用户和组-->用户-->右键属性 把"账户已禁用"前的选择符号去 ...

  2. phpcms:三、头部包含

    1‘标题:{if isset($SEO['title']) && !empty($SEO['title'])}{$SEO['title']}{/if}{$SEO['site_title ...

  3. maven install 报错Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin

    Could not calculate build plan: Plugin org.apache.maven.plugins:maven-resources-plugin:2.6 or one of ...

  4. java 读取mysql库表数据

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import ...

  5. [Javascript] How to use JavaScript's String.replace

    In JavaScript, you can change the content of a string using the replace method. This method signatur ...

  6. PHP5生成图形验证码(有汉字)

    利用PHP5中GD库生成图形验证码 类似于下面这样 1.利用GD库函数生成图片,并在图片上写指定字符 imagecreatetruecolor   新建一个真彩色图像      imagecolora ...

  7. Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类

    前言 近期做换肤功能,由于换肤程度较高,受限于平台本身,实现起来较复杂,暂时搁置了该功能,但也积累了一些经验,将分两篇文章来写这部分的内容,欢迎交流! 关键字:Android动态加载 声明 欢迎转载, ...

  8. (转) [老老实实学WCF] 第三篇 在IIS中寄存服务

    第三篇 在IIS中寄宿服务 通过前两篇的学习,我们了解了如何搭建一个最简单的WCF通信模型,包括定义和实现服务协定.配置服务.寄宿服务.通过添加服务引用的方式配置客户端并访问服务.我们对WCF的编程生 ...

  9. arraylist与List<>

    arraylist 不用规定 类型 list<>用规定类型 推荐list 这个编译检查类型  出错率低 代码质量高

  10. Js 时间间隔计算(间隔天数)

    function GetDateDiff(startDate,endDate)  {      var startTime = new Date(Date.parse(startDate.replac ...