Java优先队列(PriorityQueue)示例

本文由 ImportNew - ImportNew读者 翻译自 journaldev。如需转载本文,请先参见文章末尾处的转载要求。

文章由@Jaskey_Lam翻译。如果你也希望参与类似的系列文章翻译,可以加入我们的Java开发 和 技术翻译 小组。

我们知道队列是遵循先进先出(First-In-First-Out)模式的,但有些时候需要在队列中基于优先级处理对象。举个例子,比方说我们有一个每日交易时段生成股票报告的应用程序,需要处理大量数据并且花费很多处理时间。客户向这个应用程序发送请求时,实际上就进入了队列。我们需要首先处理优先客户再处理普通用户。在这种情况下,Java的PriorityQueue(优先队列)会很有帮助。

PriorityQueue类在Java1.5中引入并作为 Java Collections Framework 的一部分。PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。

优先队列不允许空值,而且不支持non-comparable(不可比较)的对象,比如用户自定义的类。优先队列要求使用Java Comparable和Comparator接口给对象排序,并且在排序时会按照优先级处理其中的元素。

优先队列的头是基于自然排序或者Comparator排序的最小元素。如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个。当我们获取队列时,返回队列的头对象。

优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。

PriorityQueue是非线程安全的,所以Java提供了PriorityBlockingQueue(实现BlockingQueue接口)用于Java多线程环境

我们有一个用户类Customer,它没有提供任何类型的排序。当我们用它建立优先队列时,应该为其提供一个比较器对象。

 

Customer.java

1 package com.journaldev.collections;
2  
3 public class Customer
{
4  
5     private int id;
6     private String
name;
7  
8     public Customer(int i,
String n){
9         this.id=i;
10         this.name=n;
11     }
12  
13     public int getId()
{
14         return id;
15     }
16  
17     public String
getName() {
18         return name;
19     }
20  
21 }

我们使用Java随机数生成随机用户对象。对于自然排序,我们使用Integer对象,这也是一个封装过的Java对象

下面是最终的测试代码,展示如何使用PriorityQueue:

 

PriorityQueueExample.java

1 package com.journaldev.collections;
2  
3 import java.util.Comparator;
4 import java.util.PriorityQueue;
5 import java.util.Queue;
6 import java.util.Random;
7  
8 public class PriorityQueueExample
{
9  
10     public static void main(String[]
args) {
11  
12         //优先队列自然排序示例
13         Queue<Integer>
integerPriorityQueue = 
new PriorityQueue<>(7);
14         Random
rand = 
new Random();
15         for(int i=0;i<7;i++){
16             integerPriorityQueue.add(new Integer(rand.nextInt(100)));
17         }
18         for(int i=0;i<7;i++){
19             Integer
in = integerPriorityQueue.poll();
20             System.out.println("Processing
Integer:"
+in);
21         }
22  
23         //优先队列使用示例
24         Queue<Customer>
customerPriorityQueue = 
new PriorityQueue<>(7,
idComparator);
25         addDataToQueue(customerPriorityQueue);
26  
27         pollDataFromQueue(customerPriorityQueue);
28  
29     }
30  
31     //匿名Comparator实现
32     public static Comparator<Customer>
idComparator = 
newComparator<Customer>(){
33  
34         @Override
35         public int compare(Customer
c1, Customer c2) {
36             return (int)
(c1.getId() - c2.getId());
37         }
38     };
39  
40     //用于往队列增加数据的通用方法
41     private static void addDataToQueue(Queue<Customer>
customerPriorityQueue) {
42         Random
rand = 
new Random();
43         for(int i=0;
i<
7;
i++){
44             int id
= rand.nextInt(
100);
45             customerPriorityQueue.add(new Customer(id, "Pankaj
"
+id));
46         }
47     }
48  
49     //用于从队列取数据的通用方法
50     private static void pollDataFromQueue(Queue<Customer>
customerPriorityQueue) {
51         while(true){
52             Customer
cust = customerPriorityQueue.poll();
53             if(cust
== 
nullbreak;
54             System.out.println("Processing
Customer with ID="
+cust.getId());
55         }
56     }
57  
58 }

注意我用实现了Comparator接口的Java匿名类,并且实现了基于id的比较器。

当我运行以上测试程序时,我得到以下输出:

 

1 Processing
Integer:9
2 Processing
Integer:16
3 Processing
Integer:18
4 Processing
Integer:25
5 Processing
Integer:33
6 Processing
Integer:75
7 Processing
Integer:77
8 Processing
Customer with ID=6
9 Processing
Customer with ID=20
10 Processing
Customer with ID=24
11 Processing
Customer with ID=28
12 Processing
Customer with ID=29
13 Processing
Customer with ID=82
14 Processing
Customer with ID=96

从输出结果可以清楚的看到,最小的元素在队列的头部因而最先被取出。如果不实现Comparator,在建立customerPriorityQueue时会抛出ClassCastException。

1 Exception in thread "main" java.lang.ClassCastException:
com.journaldev.collections.Customer cannot be cast to java.lang.Comparable
2     at
java.util.PriorityQueue.siftUpComparable(PriorityQueue.java:633)
3     at
java.util.PriorityQueue.siftUp(PriorityQueue.java:629)
4     at
java.util.PriorityQueue.offer(PriorityQueue.java:329)
5     at
java.util.PriorityQueue.add(PriorityQueue.java:306)
6     at
com.journaldev.collections.PriorityQueueExample.addDataToQueue(PriorityQueueExample.java:45)
7     at
com.journaldev.collections.PriorityQueueExample.main(PriorityQueueExample.java:25)

以上就是优先队列的全部内容,如果你喜欢这篇文章,请参与分享或者评论。

原文链接: journaldev 翻译: ImportNew.com ImportNew读者

译文链接: http://www.importnew.com/6932.html

时间: 2024-10-24 12:29:10

Java优先队列(PriorityQueue)示例的相关文章

java中的优先队列PriorityQueue不再维护最小优先是怎么回事

问题描述 java中的优先队列PriorityQueue不再维护最小优先是怎么回事 用最小优先队列实现Dijkstra算法出现PriorityQueue不再维护最小优先,从队列中弹出一个结点后,队列中其余结点顺序未发生改变, 导致第一个元素不是最小值 解决方案 根据API说明,这个类的队列首元素是最小的啊.你是怎么使用这个类的呢? <p>The <em>head</em> of this queue is the <em>least</em> e

解析Java中PriorityQueue优先级队列结构的源码及用法_java

一.PriorityQueue的数据结构 JDK7中PriorityQueue(优先级队列)的数据结构是二叉堆.准确的说是一个最小堆. 二叉堆是一个特殊的堆, 它近似完全二叉树.二叉堆满足特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆. 当父节点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父节点的键值总是小于或等于任何一个子节点的键值时为最小堆. 下图是一个最大堆 priorityQueue队头就是给定顺序的最小元素. prio

关于继承内部类——java编程思想示例程序分析

编程|程序|继承|示例 关于继承内部类--java编程思想示例程序分析:class Egg2 { protected class Yolk { public Yolk() { System.out.println("Egg2.Yolk()"); } public void f() { System.out.println("Egg2.Yolk.f()"); } } private Yolk y = new Yolk(); public Egg2() { System

一个简单的Java EE&amp;Docker示例

本文讲的是一个简单的Java EE&Docker示例,[编者的话]学习Docker的最好办法就是迅速在工作中应用它,本文作者使用Docker部署了一个Java EE应用,非常简单和方便.需要注意的是,由于作者写作时本地网络有问题,所以Dockerfile中很多的资源都没有从网络下载,你再实践时,可以尝试修改.学习快乐 :) 本文中,我们将会把Java EE和Docker结合,具体内容如下: 创建.构建并运行一个Docker镜像: 通过镜像启动一个Wildfly服务器,并部署了一个JavaEE示例

谁有JAVA核心技术的示例代码?

问题描述 谁有JAVA核心技术的示例代码? 解决方案 解决方案二:何谓核心?解决方案三:引用楼主ybingxin1234的回复: 谁有JAVA核心技术的示例代码? 你要的核心技术的下载包里肯定有example解决方案四:<JAVA核心技术>里的示例代码?解决方案五:JDK的安装包里....解决方案六:JDK安装包中的demo中有源码

Kafka JAVA客户端代码示例--高级应用

什么时间使用高级应用? 针对一个消息读取多次 在一个process中,仅仅处理一个topic中的一组partitions 使用事务,确保每个消息只被处理一次 使用高级应用(调用较底层函数)的缺点?     SimpleConsumer需要做很多额外的工作(在以groups方式进行消息处理时不需要) 在应用程序中跟踪上次消息处理的offset 确定一个topic partition的lead broker 手工处理broker leander的改变 使用底层函数(SimpleConsumer)开发

Java RMI 简单示例

示例 RMI是Java平台实现远程调用的规范,下面是一个小例子,本机测试通过 一共有三个java类,远程接口,服务端程序,客户端程序 远程接口: import java.rmi.*; public interface HelloIn extends java.rmi.Remote{ String sayHello() throws RemoteException;} 服务端程序: import java.rmi.*;import java.net.*;import java.rmi.regist

用java压缩文件示例(没有中文问题)

示例|问题|压缩|中文 这本是别人的东西,我只是修改了中文问题.在这个基础上改一下就可以压缩多个文件和目录,甚至可以写一个winzip之类的东东哦,有兴趣的可以研究一下.import java.io.*;import java.util.zip.*;  /**   * @version Version 1.3   */  public class w0514{       public static void main(String[] args){          try{         

Kafka JAVA客户端代码示例

介绍      http://kafka.apache.org     kafka是一种高吞吐量的分布式发布订阅消息系统     kafka是linkedin用于日志处理的分布式消息队列,linkedin的日志数据容量大,但对可靠性要求不高,其日志数据主要包括用户行为(登录.浏览.点击.分享.喜欢)以及系统运行日志(CPU.内存.磁盘.网络.系统及进程状态)      当前很多的消息队列服务提供可靠交付保证,并默认是即时消费(不适合离线).  高可靠交付对linkedin的日志不是必须的,故可通