我理解的数据结构(三)—— 队列(Queue)

一、队列

  • 队列是一种线性结构
  • 相比数组,队列对应的操作是数组的子集
  • 只能从一端(队尾)添加元素,只能从另一端(队首)取出元素
  • 队列是一种先进先出的数据结构(FIFO)

二、数组队列与循环队列

1. 数组队列

如果你有看过我之前的文章不要小看了数组或者,你就会发现,自己封装一个数组队列是如此的轻松加愉快!

(1)先定义一个接口,接口中定义队列需要实现的方法

```
public interface Queue<E> {
int getSize();
boolean isEmpty();
// 查看队首元素
E getFront();
// 入队
void enqueue(E ele);
// 出队
E dequeue();
}
```

(2)实现数组队列

```
public class ArrayQueue<E> implements Queue<E> {

// 这里的数组是在之前的文章中封装好的,直接拿来用就好了
private ArrayNew&lt;E&gt; array; public ArrayQueue(int capacity) {
array = new ArrayNew&lt;&gt;(capacity);
} public ArrayQueue() {
this(10);
} public int getCapacity() {
return array.getCapacity();
} @Override
public int getSize() {
return array.getSize();
} @Override
public boolean isEmpty() {
return array.isEmpty();
} @Override
public E getFront() {
return array.getFirst();
} @Override
public void enqueue(E ele) {
array.addLast(ele);
} @Override
public E dequeue() {
return array.removeFirst();
} @Override
public String toString() { StringBuffer res = new StringBuffer(); res.append(String.format("arrayQueue: size = %d, capacity = %d\n", getSize(), getCapacity()));
res.append("front ["); for (int i = 0; i &lt; array.getSize(); i++) {
res.append(array.get(i));
if (i != getSize() - 1) {
res.append(", ");
}
}
res.append("] tail");
return res.toString(); }

}


<p><strong>(3)数组队列的复杂度</strong></p>
<table>
<thead><tr>
<th align="center">方法</th>
<th align="center">复杂度</th>
</tr></thead>
<tbody>
<tr>
<td align="center"><code>enqueue</code></td>
<td align="center">O(1) 均摊</td>
</tr>
<tr>
<td align="center"><code>dequeue</code></td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center"><code>front</code></td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center"><code>getSize</code></td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center"><code>isEmpty</code></td>
<td align="center">O(1)</td>
</tr>
</tbody>
</table>
<blockquote>这个时候我们会发现,在进行出队操作的时候,数组队列的复杂度是0(n),如果我们频繁的进行出队操作,那么其实数组队列的效率是很低的,如何提升数组队列的性能呢?这个时候我们就要用到循环队列了。</blockquote>
<h4>2. 循环队列队列</h4>
<blockquote>循环队列的原理:</blockquote>
<ol>
<li>
<code>dequeue</code>时,不要在去除队首元素时,把整体向前移动</li>
<li>维护 <code>front</code> 、 <code>tail</code> 和 <code>size</code> 这三个属性</li>
<li>
<code>enqueue</code>的时候<code>tail++</code>
</li>
<li>
<code>dequeue</code>的时候<code>front++</code>
</li>
</ol> ![](https://img2018.cnblogs.com/blog/1504257/201811/1504257-20181117135616157-1981589685.png) <p><strong>(1)实现循环队列</strong></p>

public class LoopQueue<E> implements Queue<E> {

private E[] array;
private int size;
private int front;
private int tail; public LoopQueue(int capacity) {
// 我们需要浪费一个空间去判断队列是否已满,所以需要把capacity + 1
array = (E[])new Object[capacity + 1];
front = 0;
tail = 0;
size = 0;
} public LoopQueue() {
this(10);
} // 返回用户传递的队列大小
public int getCapacity() {
return array.length - 1;
} @Override
public int getSize() {
return size;
} @Override
public boolean isEmpty() {
return front == tail;
} @Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty. Can't get front.");
} return array[0];
} @Override
public void enqueue(E ele) { if (front == (tail + 1) % array.length) {
// 扩展队列长度为原长度2倍
resize(getCapacity() * 2);
} array[tail] = ele;
size++;
tail = (tail + 1) % array.length;
} @Override
public E dequeue() { if (isEmpty()) { // 队列为空
throw new IllegalArgumentException("Queue is empty. Can't get dequeue.");
} E ele = array[front]; size--;
array[front] = null;
front = (front + 1) % array.length; if (size == getCapacity() / 4 &amp;&amp; getCapacity() / 2 != 0) {
resize(getCapacity() / 2);
} return ele; } private void resize(int newCapacity) {
E[] newArray = (E[]) new Object[newCapacity + 1]; for (int i = 0; i &lt; size; i++) {
newArray[i] = array[(front + i) % array.length];
} array = newArray;
front = 0;
tail = size;
} @Override
public String toString() {
StringBuffer res = new StringBuffer(); res.append(String.format("queue: size = %d, capacity = %d\n", getSize(), getCapacity()));
res.append("front ["); // 循环条件,和循环增量都要注意下
for (int i = front; i != tail; i = (i + 1) % array.length) {
res.append(array[i]); if ((i + 1) % array.length != tail) {
res.append(", ");
}
}
res.append("] tail"); return res.toString();
}

}


<p><strong>(2)循环队列的复杂度</strong></p>
<table>
<thead><tr>
<th align="center">方法</th>
<th align="center">复杂度</th>
</tr></thead>
<tbody>
<tr>
<td align="center"><code>enqueue</code></td>
<td align="center">O(1) 均摊</td>
</tr>
<tr>
<td align="center"><code>dequeue</code></td>
<td align="center">O(1) 均摊</td>
</tr>
<tr>
<td align="center"><code>front</code></td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center"><code>getSize</code></td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center"><code>isEmpty</code></td>
<td align="center">O(1)</td>
</tr>
</tbody>
</table>
<h3>三、用时间说话</h3>
<p><strong>(1)用时方法</strong></p>

public static double test(Queue<Integer> q, int opCount) {

// 纳秒
long startTime = System.nanoTime(); Random random = new Random(); for (int i = 0; i &lt; opCount; i++) {
q.enqueue(random.nextInt(Integer.MAX_VALUE));
}
for (int i = 0; i &lt; opCount; i++) {
q.dequeue();
} // 纳秒
long endTime = System.nanoTime(); return (endTime - startTime) / 1000000000.0;

}


<p><strong>(2)调用</strong></p>

// 十万次入队和十万次出队操作

int opCount = 100000;

ArrayQueue<Integer> aq = new ArrayQueue<>();

double time1 = test(aq, opCount);

System.out.println(time1);

LoopQueue<Integer> lq = new LoopQueue<>();

double time2 = test(lq, opCount);

System.out.println(time2);


<p><strong>(3)结果</strong></p>
<ul>
<li>14.635995113</li>
<li>0.054536447</li>
</ul>
<blockquote>这个就是算法和数据结构的力量!</blockquote> 原文地址:https://segmentfault.com/a/1190000016147024

我理解的数据结构(三)—— 队列(Queue)的更多相关文章

  1. Python与数据结构[2] -> 队列/Queue[0] -> 数组队列的 Python 实现

    队列 / Queue 数组队列 数组队列是队列基于数组的一种实现,其实现类似于数组栈,是一种FIFO的线性数据结构. Queue: <--| 1 | 2 | 3 | 4 | 5 |<-- ...

  2. 数据结构:队列queue 函数push() pop size empty front back

    队列queue: push() pop() size() empty() front() back() push()  队列中由于是先进先出,push即在队尾插入一个元素,如:可以输出:Hello W ...

  3. 算法与数据结构基础 - 队列(Queue)

    队列基础 队列具有“先进先出”的特点,用这个特点我们可以用它来处理时间序列相关或先后次序相关的问题,例如 LeetCode题目 933. Number of Recent Calls,时间复杂度O(1 ...

  4. 数据结构之队列(queue)

    队列介绍 1.队列是一个有序列表,可以用数组或是链表来实现. 2.遵循先入先出的原则.即:先存入队列的数据,要先取出.后存入的要后取出. 应用场景 比如某某银行叫号系统: 数组模拟队列 队列本身是有序 ...

  5. Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)

    Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...

  6. Java 集合深入理解(9):Queue 队列

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情不太好,来学一下 List 吧! 什么是队列 队列是数据结构中比较重要的一种类型,它支持 FIFO,尾部添加.头部 ...

  7. 【Java数据结构学习笔记之二】Java数据结构与算法之队列(Queue)实现

      本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...

  8. 【Java数据结构学习笔记之三】Java数据结构与算法之队列(Queue)实现

      本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...

  9. 数据结构——链队列(linked queue)

    /* linkedQueue.c */ /* 链队列 */ #include <stdio.h> #include <stdlib.h> #include <stdboo ...

随机推荐

  1. 寒城攻略:Listo 教你用 Swift 写IOS UI 项目计算器

    之前总结过 Swift 的语言攻略,这里就不做赘述了,如今做一个实例计算器项目来介绍一下 Swift 的应用.(凝视已经全然.直接上代码) 先看一下效果图: 以下是详细的代码和解释: 分享快乐.开源中 ...

  2. ZOJ 3814 Sawtooth Puzzle (2014年牡丹江赛区网络赛F题)

    1.题目描写叙述:点击打开链接 2.解题思路:本题是一道隐式图的搜索题目.一般来说,这类题目首先要定义状态,接下来是弄清楚状态怎样转移,以及状态怎样判重,怎样推断当前状态是否和目标状态同样.至于求解最 ...

  3. 【Linux】Linux下配置apache

    一.获取软件: http://httpd.apache.org/   httpd-2.4.10.tar.gz 二.安装步骤: 解压源文件: 1) tar zvxf  httpd-2.4.10.tar. ...

  4. hdu 1213(并查集模版题)

    How Many Tables Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  5. Coursera Algorithms week3 归并排序 练习测验: Merging with smaller auxiliary array

    题目原文: Suppose that the subarray a[0] to a[n-1] is sorted and the subarray a[n] to a[2*n-1] is sorted ...

  6. 通过DOM实现点击隐藏父元素

    HTML代码简单如下: <ul id='ul1'> <li><a href="javascript:">1</a></li&g ...

  7. css3 选择器 权重问题 (第二部分)

    这篇博文有关css的权重问题,我个人认为这是css知识中很重要的一个知识点.因为在开发的过程能中我们会经常遇到这种问题,特别是如果你使用框架的时候,有些框架的某些标签有一些默认的样式.所以我们可以通过 ...

  8. CAS配置(1)SSL证书配置

    一.配置源码 源码配置稍后提供 二.系统环境安装 安装JDK配置,版本>=1.7 环境变量配置(参考): JAVA_HOME=C:\Program Files x86)\Java\jdk1.7. ...

  9. POJ 1010 题目翻译+题解

    题目实在是太难懂了,我翻译了一下... STAMPS Description Have you done any Philately lately? 你最近有没有集邮? You have been h ...

  10. Spring Boot (11) mybatis 关联映射

    一对多 查询category中的某一条数据,同时查询该分类下的所有Product. Category.java public class Category { private Integer id; ...