Java中队列
定义
队的操作是在两端进行,一端只能进行插入操作(入队),称为队尾,一端只能进行删除操作(出队),称为队尾。
队列的运算规则是FIFO
(first in first out)。
队列的入队、出队操作分别具有入队和出队的指针,通常以f(front) 表示队首指针,r(rear)表示队尾指针。
队列的存储具有顺序存储和链式存储两种方式。
基本运算:
- 初始化;
- 判断空;
- 判断满;
- 入队;
- 出队;
- 取出队首元素。
package com.wuwii.test;
/**
* 队列
* @author Zhang Kai
* @version 1.0
* @since <pre>2017/12/17 13:12</pre>
*/
public interface Queue<E> {
/**
* 入队
* @param element 入队元素
*/
void enqueue(E element);
/**
* 出队第一个元素
* @return 第一个元素
*/
E dequeue();
/**
* 返回队首的元素
* @return E 队首元素
*/
E frontValue();
/**
* 清空队列的所有元素
*/
void clear();
/**
* 判断队列是否为空
* @return true 为空,
*/
Boolean isEmpty();
}
顺序队列
。由于顺序存储结构的空间是连续的,需要一个向量空间存储当前队列的所有元素,由于队列的对头和队尾的位置是变化的。初始化的时候,rear 和front 都设置为 0 ;入队的时候将新元素插入rear 所指的位置,然后将rear 加 1 ;出队的时候,删除 front 所指的元素,然后将 front 加 1并返回该元素。由此可见,当头尾指针相等时队列为空。在非空队列中,头指针始终指向队头元素,而尾指针始终指向队尾元素的下个位置。
这里其实存在一个问题需要解决。队列的顺序存储结构同样也存在上溢和下溢的问题。而且,队列中还存在假溢出
现象,指的是队列在入队和出队的操作中,头尾指针不断增加而不减少或者只减少而不增加,导致被删除的元素的空间无法重新利用,因此,尽管队列中实际的元素个数远远小于向量空间的规模,但也可能由于尾指针已远远超越向量空间的上界而不能进行入队或出队的操作,这种现象称为假上溢。
解决假上溢有多种方法。
- 固定头指针:固定队首指针,一旦删除元素,需要移动所有元素,然后修改队尾指针,这样就又可以插入元素,只有在不能插入元素的时候,队列才是满的,否则可以一直插入元素,但是也存在一个,每次删除元素的时候,都移动了大量的数据,造成性能损失;
- 循环向量:存储在循环向量的队列成为循环队列。
循环队列
存储在循环向量的队列成为循环队列
假设向量的空间为m,只要在入队或者出队操作的时候,将队首和队尾的指针对m做求模运算即可实现队首和队尾指针的循环,因此,队首和队尾指针的数值取值范围为0 ~ m-1 之间。
入队时:rear = (rear + 1) % maxSize
;
出队时:front = (front + 1) % maxSize
;
入队时,rear指针不断加一,知道rear 指针追上 front 指针的时候,队列满,rear = front,出队的时候,只需要判断 front = rear。因此,又出现了一个问题,判断队列的空与满的条件相同。
区分队列的空与满:
- 方式一:浪费一个空间;rear指向刚刚插入的位置,front指向刚刚插入的位置;入队的时候先不修改rear 指针,先去判断
(rear + 1) % maxSize = front
,成立,表示队列已经满了。出队的时候只需要判断 front = rear,不为空的话,删除front = (front + 1) % maxSize
位置的元素。 - 方式二:设定一个变量来保存存储的元素个数;将该变量跟队列最大容量进行比较,如果相等,则队列满,如果该变量为0,表示队列为空。
上面两种方式都需要消费一个存储单元。
实现循环队列需要两个指针的开销,需要定义数组的最大下标范围,遵循先进先出原则。
package com.wuwii.test;
/**
* 顺序队列 -》循环队列
* @author Zhang Kai
* @version 1.0
* @since <pre>2017/12/17 13:17</pre>
*/
public class Squeue<E> implements Queue<E> {
/**
* 队列默认大小
*/
private final int defaultSize = 10;
/**
* 队列存储的元素个数
*/
private int size;
/**
* 队首位置
*/
private int front;
/**
* 队尾位置
*/
private int rear;
/**
* 存储数组
*/
private Object[] elements;
/**
* 无参构造,使用默认大小10
*/
public Squeue() {
initQueue(defaultSize);
}
/**
* 有参构造,指定队列大小
* @param givenSize 需要指定队列大小
*/
public Squeue(int givenSize) {
initQueue(givenSize);
}
/**
* 入队
*
* @param element 入队元素
*/
@Override
public void enqueue(E element) {
checkFull();
rear = (rear + 1) % size;
elements[rear] = element;
}
/**
* 出队第一个元素
*
* @return 第一个元素
*/
@Override
public E dequeue() {
checkEmpty();
front = (front + 1) % size;
return (E) elements[front];
}
/**
* 返回队首的元素
*
* @return E 队首元素
*/
@Override
public E frontValue() {
return (E) elements[(front + 1) % size];
}
/**
* 清空队列的所有元素
*/
@Override
public void clear() {
if (isEmpty()) {
return;
}
front = rear = 0;
}
/**
* 判断队列是否为空
*
* @return true 为空,
*/
@Override
public Boolean isEmpty() {
return front == rear;
}
/**
* 初始化队列
* @param givenSize 给定大小
*/
private void initQueue(int givenSize) {
size = givenSize + 1;
front = rear = 0;
elements = new Object[size];
}
/**
* 检查队列满
* 队列满了抛出异常
*/
private void checkFull() {
if (front == (rear + 1) % size) {
throw new RuntimeException("Queue is full");
}
}
/**
* 检查队列为空
* 为空抛出异常
*/
private void checkEmpty() {
if (isEmpty()) {
throw new RuntimeException("Queue is empty");
}
}
}
链式队列
相比顺序队列,链式队列的队首和队尾改为指针。
链式队列存在一个很方便的特点,只需要一个队尾指针就可以完成队列所有的基本运算,主要原因就是队列的运算方式时先进先出,已知一个任意节点,就可以查找出所有,所以只需要一个队尾就可以了,节约空间开销。
清空队列只需要将指针删除即可。
package com.wuwii.test;
/**
* 链式队列,循环队列
* @author Zhang Kai
* @version 1.0
* @since <pre>2017/12/17 14:14</pre>
*/
public class LinkQueue<E> implements Queue<E> {
/**
* 队首指针
*/
private Node<E> front;
/**
* 队尾指针
*/
private Node<E> rear;
public LinkQueue() {
initQueue();
}
/**
* 入队
*
* @param element 入队元素
*/
@Override
public void enqueue(E element) {
if (rear == null) {
rear = new Node<>(null, element);
} else {
front = rear = new Node<>(null, element);
}
}
/**
* 出队第一个元素
*
* @return 第一个元素
*/
@Override
public E dequeue() {
checkEmpty();
E e = front.element;
front = front.next;
return e;
}
/**
* 返回队首的元素
*
* @return E 队首元素
*/
@Override
public E frontValue() {
return front.element;
}
/**
* 清空队列的所有元素
*/
@Override
public void clear() {
front = rear = null;
}
/**
* 判断队列是否为空
*
* @return true 为空,
*/
@Override
public Boolean isEmpty() {
return rear == null;
}
/**
* 存储单元,链表单元
* @param <E>
*/
private static class Node<E> {
Node<E> next;
E element;
Node(Node<E> next, E element) {
this.next = next;
this.element = element;
}
}
/**
* 初始化队列
*/
private void initQueue() {
front = rear = null;
}
/**
* 检查队列为空
* 为空抛出异常
*/
private void checkEmpty() {
if (isEmpty()) {
throw new RuntimeException("Queue is empty");
}
}
}
Java中队列的更多相关文章
- Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理
前言 在 Java 中通过锁来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关 ...
- Java 中队列的使用
刚才看见群里的一个朋友在问队列的使用,确实在现实的写代码中非常少使用队列的,反正我是从来没使用过.仅仅是学数据结构的时候学过. 以下是我写的一个小样例,希望有不足之处请提出改正.O(∩_∩)O~ 看代 ...
- java中队列Queue的使用
1.在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.Queue接口与List.Set同一级别,都是继承了Collection接口.Queue使用时要尽量避免Colle ...
- Java中常用七个阻塞队列的总结
Java队列总结 通过前面文章的学习,我们对Java中常用队列做了介绍.本文,咱们来对队列做个总结吧. 首先,我们介绍了现实生活中的实际场景(排队买票等),来告诉我们为什么需要使用队列. 队列是一种先 ...
- JAVA中常见的阻塞队列详解
在之前的线程池的介绍中我们看到了很多阻塞队列,这篇文章我们主要来说说阻塞队列的事. 阻塞队列也就是 BlockingQueue ,这个类是一个接 口,同时继承了 Queue 接口,这两个接口都是在JD ...
- Java Queue 队列
队列是一种先进先出的数据结构,队列中插入元素和删除元素分别位于队列的两端. 在Java中 队列实现类众多,本文不再赘述.本文探讨的是如何自定义队列实现类: 基于数组方式实现队列: 注意点: 当出队时队 ...
- 聊聊并发(七)——Java中的阻塞队列
3. 阻塞队列的实现原理 聊聊并发(七)--Java中的阻塞队列 作者 方腾飞 发布于 2013年12月18日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办,了解更 ...
- Java中的自定义数组队列
在Java中,作为所有数据结构中存储和获取速度最快的一种,数组凭借其这种简单易用的优势在各个方面都能大显神威.但是数组也有自身的局限性.数组的长度必须是固定的一旦定义之后就无法动态的更改,这就会造成这 ...
- 延时队列:Java中的DelayQueue
Java中的DelayQueue位于java.util.concurrent包下,本质是由PriorityQueue和BlockingQueue实现的阻塞优先级队列. 放入队列的元素需要实现java. ...
随机推荐
- Teamviewer 手机端怎么拖动窗口,选中文字
Teamviewer 手机端怎么拖动窗口,选中文字 Teamviewer 手机端拖动窗口,选中文字和触摸板的使用方式是一样的 点两下不松开就可以拖动 点两下不松开也可以选中文字 Teamviewer ...
- jenkins集成caliper"
1.jenkins安装caliper-ci插件(Caliper CI Plugin) 2.编写microbench 最简便的办法就是作为单元测试来跑(这样就不用在jenkins里配置跑microben ...
- 关于sys.dm_exec_requests
我知道SQL Server有很多视图和函数让我来了解SQL Server的运行状态.我还想知道SQL Server上关于来自用户或者应用的活动请求信息.怎么查询这些信息呢? SQL Server的动态 ...
- Mysql5.7 的错误日志中最常见的note级别日志解释
在使用mysql5.7的时候,发现了不少在mysql5.6上不曾见过的日志,级别为note, 最常见的note日志以下三种,下面我们来逐个解释. 第一种,Aborted connectio ...
- [翻译] NSImage+HHTint - Tints grayscale images using CoreImage
NSImage+HHTint - Tints grayscale images using CoreImage https://github.com/gloubibou/NSImage-HHTint ...
- python 下字符串格式时间比较
python 下有多个有关时间的模块,分别是time.datetime.calendar,今天重点讨论下time写法. 其中time模块,主要有以下方法: ltime=time.time() 获取当前 ...
- python3: 字符串和文本(3)
11. 删除字符串中不需要的字符 strip() 方法能用于删除开始或结尾的字符: lstrip() 和 rstrip() 分别从左和从右执行删除操作 >>> s = ' hell ...
- java Math数学工具及Random随机函数
Math类包含用于执行基本数学运算的方法,如绝对值.对数.平方根和三角函数.它是一个final类,其中定义的都是一些常量和静 态方法.常用方法如下:public static double sqrt( ...
- chrome开发者工具那点事
Elements:查找网页源代码HTML中的任一元素,手动修改任一元素的属性和样式且能实时在浏览器里面得到反馈. Console:记录开发者开发过程中的日志信息,且可以作为与JS进行交互的命令行She ...
- swift的Hashable
Conforming to the Hashable Protocol To use your own custom type in a set or as the key type of a dic ...