“队列”这个单词是英国人说的“排”。在英国“排队”的意思就是站到一排当中去。计算机科学中,队列是一种数据结构,有点类似栈,只是在队列中第一个插入的数据项也会最先被移除,而在栈中,最后插入的数据项最先移除。队列的作用就像电影院前的人们站成的排一样:第一个进入附属的人将最先到达队头买票。最后排队的人最后才能买到票。

队列和栈一样也被用作程序员的工具。它也可以用于模拟真实世界的环境,例如模拟人们在银行里排队等待,飞机等待起飞,或者因特网络上数据包等待传送。

在计算机操作系统里,有各种队列在安静地工作着。打印作业在打印队列中等待打印。当在键盘上敲击时,也有一个存储键入内容的队列。同样,如果使用文字处理程序敲击一个键,而计算机又暂时要做其它的事,敲击的内容不会丢失,它会排在队列中等待,直到文字处理程序有时间来读取它。利用队列保证了键入内容在处理时其顺序不会改变。

队列的基本操作

队列的两个基本操作是inserting(插入)一个数据项,即把一个数据项放入队尾,另一个是removing(移除)一个数据项,即移除队头的数据项。这类似于电影爱好者排队买票时先排到队尾,然后到达队头买票后离开队列。

栈中的插入和移除数据项方法的命名是很标准,称为push和pop。队列的方法至今没有标准化的命名。“插入”可以称为put、add或 enque,而“删除”可以叫delete、get或deque。插入数据项的队尾,也可以叫作back、tail或end。而移除数据项的队头,也可以叫head。下面将使用insert、remove、front和rear。

插入将值插入队尾,同时队尾箭头增加一,指向新的数据项。

数据项被移除后,同时队头指针增加一。通常实现队列时,删除的数据项还会保存在内存中,只是它不能被访问了,因为队头指针已经移到它的下一个位置了。

和栈中的情况不同,队列中的数据项不总是从数组的0下标处开始。移除了一些数据项后,队头指针会指向一个较高的下标位置。

查看操作返回队头数据项的值,然而并不从队中删除这个数据项。

要是想从空队列中移除一个数据项或想在已经满的队列中插入一个数据项,应用程序都要提示出错消息。

循环队列

当在队列中插入一个新数据项,队头的Rear箭头向上移动,移向数组下标大的位置。移除数据项时,队尾Front指针也会向上移动。这种设计可能和人们直观察觉相反,因为人们在买电影票排队时,队伍总是向前移动的,当前面的人买完票离开队伍后,其他人都向前移动。计算机中在队列里删除一个数据项后,也可以将其他数据项都向前移动,但这样做的效率很差。相反,我们通过队列中队头和队尾指针的移动保持所有数据项的位置不变。

这样设计的问题是队尾指针很快就会移到数组的末端。虽然在数组的开始部分有空的数据项单元,这是移除的数据项的位置,但是由于因为队尾指针不能再向后移动了,因此也不能再插入新的数据项,这该怎么办?

环绕式处理

为了避免队列不满却不能插入新数据项的问题,可以让队头队尾指针绕回到数组开始的位置。这就是循环队列(有时也称为“缓冲环”)。

指针回绕的过程:在队列中插入足够多的数据项,使队尾指针指向数组的未端。再删除几个数组前端的数据项。现在插入一个新的数据项。就会看到队尾指针从未端回绕到开始处的位置。新的数据项将插入这个位置。

插入更多的数据项。队尾指针如预计的那样向上移动。注意在队尾指针回绕之后, 它现在处在队头指针的下面,这就颠倒了初始的位置。这可以称为“折断的序列”:队列中的数据项存在数组两个不同的序列中。

删除足够多的数据项后,队头指针也回绕。这时队列的指针回到了初始运行时的位置状态,队头指针在队尾指针的下面。数据项也恢复为单一的连续的序列。

队列的Java代码

Queue.java程序创建了一个Queue类,它有insert()、remove()、peek()、isEmpty()和size()方法。

package 栈和队列;

class Queue{

privateint maxSize;

privatelong[] queArray;

privateint front;

privateint rear;

privateint nItems;

publicQueue(int s){

maxSize=s;

queArray=new long[maxSize];

front=0;

rear=-1;

nItems=0;

}

publicvoid insert(long j){

if(rear==maxSize-1)

rear=-1;

queArray[++rear]=j;

nItems++;

}

publiclong remove(){

long temp=queArray[front++];

if(front==maxSize)

front=0;

nItems--;

return temp;

}

publiclong peekFront(){

return queArray[front];

}

publicboolean isEmpty(){

return (nItems==0);

}

publicboolean ifFull(){

return (nItems==maxSize);

}

publicint size(){

return nItems;

}

}

程序实现的Queue类中不但有front(队头)和rear(队尾)字段,还有队列中当前数据项的个数:nItems。

Insert()方法运行的前提条件是队列不满。在Main()中没有显示这个方法,不过通常应该先调用isFull()方法并且返回false
后,才调用insert()方法。(更通用的做法是在insert()方法中加入检查队列是否满的判定,如果出现向已满队列里插入数据项的情况就抛出异常。)

一般情况,插入操作是rear(队尾指针)加一后,在队尾指针所指的位置处插入新的数据。但是,当rear指针指向数组的顶端,即 maxSize-1位置的时候,在插入数据项之前,它必须回绕到数组的底端。回绕操作把rear设置为-1,因此当rear加1后,它等于0,是数组底端的下标值,最后nItem加一。

Remove()方法运行的前提条件是队列不空,在调用这个方法之前应该调用isEmpty()方法确保队列不空,或者在remove()方法里加入这种出错检查的机制。

移除(remove)操作总是由front指针得到队头数据项的值,然后将front加一。但是,如果这样做使front的值超过数组的顶端,front就必须绕回到数组下标为0的位置上。作这种检验的同时,先将返回值临时存储起来。最后nItem减一。

Peek()方法简单易懂:它返回front指针所指数据项的值。有些队列的实现也允许查看队列队尾数据项的值;比如这些方法可称为peekFront()、peekRear()、或者只是front()和rear()。

isEmpty()、isFull()和size()方法的实现都依赖于nItems字段,它们分别返回nItems是否等于0,是否等于maxSize,或者返回它本身值。

在Queue类中包含数据项计数字段nItems会使insert()和remove()方法增加一点额外的操作,因为insert()和 remove()方法必须分别递增和递减这个变量值。这可能算不上额外的开销,但是如果处理大量的插入和移除操作,这就可能会影响性能了。

因为,一些队列的实现不使用数据项计数的字段,而是通过front和rear来计算出队列是否空或者满以及数据项的个数。如果这样做,isEmpty()、ifFull()和size()例程会相当复杂,因为就像前面讲过的那样,数据项的序列或者被折成两段,或者是连续的一段。

而且,一个奇怪的问题出现了。当队列满的时候,front和rear指针取一定的位置,但是当队列为空时,也可能呈现相同的位置关系。于是在同一时间,队列似乎可能是满的,也可能是空的。这个问题的解决方法是:让数组容量比队列数据项个数的最大值学要大一。

java队列的更多相关文章

  1. java队列Queue及阻塞队列

    java队列 接口Queue类在java.util包,定义了以下6个方法 详细查看官方文档https://docs.oracle.com/javase/7/docs/api/java/util/Que ...

  2. JAVA队列的使用

    JAVA队列的使用 今天跟大家来看看如何在项目中使用队列.首先我们要知道使用队列的目的是什么?一般情况下,如果是一些及时消息的处理,并且处理时间很短的情况下是不需要使用队列的,直接阻塞式的方法调用就可 ...

  3. Java:Java 队列的遍历

    Java队列到底有没有可以遍历的功能呢?暂且试一下吧 参考链接:stl容器遍历测试 1.LinkedList实现简单遍历 for(Iter =LocTimesSerials.size()-1; iSe ...

  4. Java队列集合的性能测试

    同时开10个线程存入和取出100万的数据,结论如下: DoubleBufferedQueue < ConcurrentLinkedQueue < ArrayBlockingQueue &l ...

  5. java队列——queue详细分析

    Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构 Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Deque接 口.   Q ...

  6. Java队列学习

    队列是Java集合中的重要组成部分,具有先进先出的特性,使其具有广泛的应用场景,比如排队等.因此今天就来学习一下Java中的队列.本文的例子使用的Java8环境. 继承类图 学习队列,首先要知道它的类 ...

  7. Java队列Queue

    上个星期总结了一下synchronized相关的知识,这次将Queue相关的知识总结一下,和朋友们分享. 在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列.Java提供 ...

  8. Java队列——线程池创建的例子

    线程池为线程生命周期开销问题和资源不足问题提供了解决方案.通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上.其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟.这 ...

  9. Java队列——Disruptor 的使用

    .什么是 Disruptor  从功能上来看,Disruptor 是实现了“队列”的功能,而且是一个有界队列.那么它的应用场景自然就是“生产者-消费者”模型的应用场合了. 可以拿 JDK 的 Bloc ...

随机推荐

  1. linux iio子系统

    //============================================================================\\ || 系            统:W ...

  2. C语言--测试电脑存储模式(大端存储OR小端存储)

    相信大家都知道大端存储和小端存储的概念,这在平时,我们一般不用考虑,但是,在某些场合,这些概念就显得很重要,比如,在 Socket 通信时,我们的电脑是小端存储模式,可是传送数据或者消息给对方电脑时, ...

  3. 学习Tensorflow,使用源码安装

    PC上装好Ubuntu系统,我们一步一步来讲解如何使用源码安装tensorflow?(我的Ubuntu系统是15.10) 安装cuda 根据你的系统型号选择相应的cuda版本下载 https://de ...

  4. path和classpath的区别

    path的作用 path是系统用来指定可执行文件的完整路径,即使不在path中设置JDK的路径也可执行JAVA文件,但必须把完整的路径写出来,如C:\Program Files\Java\jdk1.6 ...

  5. springMVC源码分析--容器初始化(一)ContextLoaderListener

    在spring Web中,需要初始化IOC容器,用于存放我们注入的各种对象.当tomcat启动时首先会初始化一个web对应的IOC容器,用于初始化和注入各种我们在web运行过程中需要的对象.当tomc ...

  6. FFmpeg获取DirectShow设备数据(摄像头,录屏)

    这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘.本文所述的方法主要是对应Windows平台的. 1.       列设备 ffmpeg -list_devic ...

  7. Android官方命令深入分析之etc1tool

    etc1tool是一个命令行工具,可以将PNG图像压缩为etc1标准,并且可以进行解压缩. 用法: etc1tool infile [--help | --encode | --encodeNoHea ...

  8. JavaScript压缩工具JSA使用介绍

    JavaScript压缩工具JSA使用介绍 JSA绝对是我使用过的JS压缩工具中最上乘的一个.认识它是从ligerUI开始.在ligerUI的QQ讨论组里,大神--ligerUI的作者告诉我他的lig ...

  9. 如何利用BI搭建电商数据分析平台

    某电商是某大型服装集团下的重要销售平台.2015 年,该集团品牌价值达数百亿元,产品质量.市场占有率.出口创汇.销售收入连年居全国绒纺行业第一,在中国有终端店3000多家,零售额80 亿.其羊绒制品年 ...

  10. URI记录

    URI:统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串.该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互 ...