定义

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

队列的运算规则是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. Eclipse 校验取消

    eclipse Multiple annotations found at this line错误,eclipse开发过程中,一些XML配置文件会报错,但是这些其实不是错,飘红的原因是因为eclips ...

  2. 6_1 持久化模型与再次加载_探讨(1)_三种持久化模型加载方式以及import_meta_graph方式加载持久化模型会存在的变量管理命名混淆的问题

    笔者提交到gitHub上的问题描述地址是:https://github.com/tensorflow/tensorflow/issues/20140 三种持久化模型加载方式的一个小结论 加载持久化模型 ...

  3. Software Project Management 2017 Homework 1

    Recently, I have a project, I use Unity3D to finish a visualization work, which is the final project ...

  4. 使用Percona MySQL 5.7版本遇到的坑

    监控DB由于使用的TokuDB引擎,因此选择使用Percona MySQL 5.7版本,在使用过程中遇到了比较多的坑,在这里做一下简单的记录,希望对广大DBA有帮助. load文件飙升导致的DB雪崩 ...

  5. 转:C# WinForm窗体及其控件的自适应

    一.说明 2012-11-30 曾经写过 <C# WinForm窗体及其控件自适应各种屏幕分辨率>  ,其中也讲解了控件自适应的原理.近期有网友说,装在panel里面的控件,没有效果? 这 ...

  6. 使用AHKActionSheet

    使用AHKActionSheet https://github.com/fastred/AHKActionSheet 基本配置代码: AHKActionSheet *actionSheet = [[A ...

  7. spider-抓取页面内容

    # -*- coding: UTF-8 -*- from HTMLParser import HTMLParser import sys,urllib2,string,re,json reload(s ...

  8. oracle 数据库数据备份

    oracle 数据库数据备份 1.使用oracle用户应该就可以进行数据备份(不需要root用户):su oracle 查oracle实例名:echo $ORACLE_SID       例如查出来的 ...

  9. 魅力python------if - else 语句

    引入:if-else的作用,满足一个条件做什么,否则做什么. if-else语句语法结构 if 判断条件: 要执行的代码 else: 要执行的代码 判断条件:一般为关系表达式或bool类型的值 执行过 ...

  10. Springboot+RestTemplate 简单使用

        spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值 ...