定义

队的操作是在两端进行,一端只能进行插入操作(入队),称为队尾,一端只能进行删除操作(出队),称为队尾。

队列的运算规则是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中队列的更多相关文章

  1. Java 中队列同步器 AQS(AbstractQueuedSynchronizer)实现原理

    前言 在 Java 中通过锁来控制多个线程对共享资源的访问,使用 Java 编程语言开发的朋友都知道,可以通过 synchronized 关键字来实现锁的功能,它可以隐式的获取锁,也就是说我们使用该关 ...

  2. Java 中队列的使用

    刚才看见群里的一个朋友在问队列的使用,确实在现实的写代码中非常少使用队列的,反正我是从来没使用过.仅仅是学数据结构的时候学过. 以下是我写的一个小样例,希望有不足之处请提出改正.O(∩_∩)O~ 看代 ...

  3. java中队列Queue的使用

    1.在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.Queue接口与List.Set同一级别,都是继承了Collection接口.Queue使用时要尽量避免Colle ...

  4. Java中常用七个阻塞队列的总结

    Java队列总结 通过前面文章的学习,我们对Java中常用队列做了介绍.本文,咱们来对队列做个总结吧. 首先,我们介绍了现实生活中的实际场景(排队买票等),来告诉我们为什么需要使用队列. 队列是一种先 ...

  5. JAVA中常见的阻塞队列详解

    在之前的线程池的介绍中我们看到了很多阻塞队列,这篇文章我们主要来说说阻塞队列的事. 阻塞队列也就是 BlockingQueue ,这个类是一个接 口,同时继承了 Queue 接口,这两个接口都是在JD ...

  6. Java Queue 队列

    队列是一种先进先出的数据结构,队列中插入元素和删除元素分别位于队列的两端. 在Java中 队列实现类众多,本文不再赘述.本文探讨的是如何自定义队列实现类: 基于数组方式实现队列: 注意点: 当出队时队 ...

  7. 聊聊并发(七)——Java中的阻塞队列

    3. 阻塞队列的实现原理 聊聊并发(七)--Java中的阻塞队列 作者 方腾飞 发布于 2013年12月18日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办,了解更 ...

  8. Java中的自定义数组队列

    在Java中,作为所有数据结构中存储和获取速度最快的一种,数组凭借其这种简单易用的优势在各个方面都能大显神威.但是数组也有自身的局限性.数组的长度必须是固定的一旦定义之后就无法动态的更改,这就会造成这 ...

  9. 延时队列:Java中的DelayQueue

    Java中的DelayQueue位于java.util.concurrent包下,本质是由PriorityQueue和BlockingQueue实现的阻塞优先级队列. 放入队列的元素需要实现java. ...

随机推荐

  1. windows域渗透实战

    测试环境 域控: 192.168.211.130 已经控制的机器: 192.168.211.133 获取网络信息 查看机器的网络信息 ipconfig /all # 查看 网卡信息,获取dns 服务器 ...

  2. ORACLE 导出表结构及备注

    https://blog.csdn.net/u013303551/article/details/52354230 SELECT t.table_name,       t.colUMN_NAME,  ...

  3. maven windows环境nexus3.0私服搭建

    下载 nexus3.x.x 需要JDK1.8版本到sonatype官网下载开源免费的OSS版本,OSS即为Open Source Software.下载地址:https://www.sonatype. ...

  4. Pycharm Html CSS JS 快捷方式创建元素

    div#div1>ol>li.id*4 tab键 <div id="div1"> <ol> <li id="id"&g ...

  5. [C++] 用Xcode来写C++程序[6] Name visibility

    用Xcode来写C++程序[6] Name visibility 此小结包括了命名空间的一些使用细节 命名空间 #include <iostream> using namespace st ...

  6. Linux内核态和用户态

    两张图说明Linux内核态和用户态之间的关系

  7. Linux cal命令详解

    cal 显示指定月份的日历 常见命令参数 NAME cal - displays a calendar SYNOPSIS cal [-smjy13] [[[day] month] year] DESC ...

  8. git did not exit cleanly (exit code 128)

    github,pull和push的时候出问题,提示git did not exit cleanly (exit code 128) 使用HTTP格式的url,不要使用SSH格式的url,在官网上赋值下 ...

  9. springboot+mybatis+mysql创建简单web后台项目

    第一步:搭建框架 新建进入这个页面 新建名字,第一次可以默认,然后下一步 第三步:选择依赖 第四步:新建项目名和存放项目路径(你可以新建一个文件夹存放) 点击finish,首次创建Springboot ...

  10. xdebug安装及使用小结

    最近安装了一下xedug,并且学习了一下如何使用.安装xdebug的初衷是为了深入研究一下PHP的垃圾回收机制. Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪, ...