我理解的数据结构(三)—— 队列(Queue)
我理解的数据结构(三)—— 队列(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<E> array;
public ArrayQueue(int capacity) {
array = new ArrayNew<>(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 < 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>

<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 && 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 < 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 < opCount; i++) {
q.enqueue(random.nextInt(Integer.MAX_VALUE));
}
for (int i = 0; i < 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)的更多相关文章
- Python与数据结构[2] -> 队列/Queue[0] -> 数组队列的 Python 实现
队列 / Queue 数组队列 数组队列是队列基于数组的一种实现,其实现类似于数组栈,是一种FIFO的线性数据结构. Queue: <--| 1 | 2 | 3 | 4 | 5 |<-- ...
- 数据结构:队列queue 函数push() pop size empty front back
队列queue: push() pop() size() empty() front() back() push() 队列中由于是先进先出,push即在队尾插入一个元素,如:可以输出:Hello W ...
- 算法与数据结构基础 - 队列(Queue)
队列基础 队列具有“先进先出”的特点,用这个特点我们可以用它来处理时间序列相关或先后次序相关的问题,例如 LeetCode题目 933. Number of Recent Calls,时间复杂度O(1 ...
- 数据结构之队列(queue)
队列介绍 1.队列是一个有序列表,可以用数组或是链表来实现. 2.遵循先入先出的原则.即:先存入队列的数据,要先取出.后存入的要后取出. 应用场景 比如某某银行叫号系统: 数组模拟队列 队列本身是有序 ...
- Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)
Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...
- Java 集合深入理解(9):Queue 队列
点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情不太好,来学一下 List 吧! 什么是队列 队列是数据结构中比较重要的一种类型,它支持 FIFO,尾部添加.头部 ...
- 【Java数据结构学习笔记之二】Java数据结构与算法之队列(Queue)实现
本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...
- 【Java数据结构学习笔记之三】Java数据结构与算法之队列(Queue)实现
本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...
- 数据结构——链队列(linked queue)
/* linkedQueue.c */ /* 链队列 */ #include <stdio.h> #include <stdlib.h> #include <stdboo ...
随机推荐
- 摘:SQL 常见题练习
--.学生表 Student(SId,Sname,Sage,Ssex) --SId 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --.课程表 Course(CId,Cnam ...
- android graphic(15)—fence
为何须要fence fence怎样使用 软件实现的opengl 硬件实现的opengl 上层使用canvas画图 上层使用opengl画图 下层合成 updateTexImage doComposeS ...
- 学习笔记——SQL SERVER的递归
SQL SERVER似乎天然具有支持递归的属性. 1.比如说,有几次,我编写或修改存储过程的时候,为图方便,在末尾随手写上 执行这个存储过程 的语句,比如 [sql] view plaincopy A ...
- 【Git学习笔记】用git pull取回远程仓库某个分支的更新,再与本地的指定分支自动merge【转】
本文转载自:http://blog.csdn.net/liuchunming033/article/details/45367629 git pull的作用是,从远程库中获取某个分支的更新,再与本地指 ...
- DBI(i80)/DPI(RGB)/DSI【转】
本文转载自:http://blog.csdn.net/liuxd3000/article/details/17437317 (1)DBI接口 A,也就是通常所讲的MCU借口,俗称80 system接口 ...
- Android 系统开机logo的修改【转】
本文转载自:http://blog.csdn.net/yandongqiangZHRJ/article/details/8585273 看到了好几个修改logo的博文,但是说的不是很清楚,在这里亲手送 ...
- Error-Java-IJ:Imported project refers to unknown jdks JavaSE-1.7
ylbtech-Error-Java-IJ:Imported project refers to unknown jdks JavaSE-1.7 Import from EclipseImported ...
- leetcode数学相关
目录 166分数到小数 169/229求众数 238除自身以外数组的乘积 69Sqrt(x) 求平方根 231Power of Two 166分数到小数 给定两个整数,分别表示分数的分子 numera ...
- HDU 4474 Yet Another Multiple Problem BFS
题意:求m的倍数中不包含一些数码的最小倍数数码是多少.比如15 ,不包含0 1 3,答案是45. BFS过程:用b[]记录可用的数码.设一棵树,树根为-1.树根的孩子是所有可用的数码,孩子的孩子也是 ...
- css 继承性和层叠性
css有两大特性:继承性和层叠性 继承性 面向对象语言都会存在继承的概念,在面向对象语言中,继承的特点:继承了父类的属性和方法.那么我们现在主要研究css,css就是在设置属性的.不会牵扯到方法的层面 ...