我理解的数据结构(三)—— 队列(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. hdu1542 线段树+扫描线+离散化

    仅仅想说题目给的欲实际不服     还是这类型的水题吧   建议看之前我写的那个 #include<stdio.h> #include<string.h> #include&l ...

  2. CSS3动画遮罩文字特效

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  3. 【译文】利用STAN做贝叶斯回归分析:Part 2 非正态回归

    [译文]利用STAN做贝叶斯回归分析:Part 2 非正态回归 作者 Lionel Hertzogn 前一篇文章已经介绍了怎样在R中调用STAN对正态数据进行贝叶斯回归.本文则将利用三个样例来演示怎样 ...

  4. 5分钟快速构建苹果IPA免费发布服务器

    在ios的开发中, 通过苹果的各种秘钥加密, 我们会生成一个.ipa文件,这就是我们的应用软件的安装包. 这个文件是能被安装到iphone/ipad上的.可是,如何才能让不在身边的人安装上这个应用呢? ...

  5. [RK3288][Android6.0] 调试笔记 --- 普通串口的添加 【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/54574073   标签: rk3288 串口添加 2017-01-16 14:52 1079 ...

  6. operator[] 重载

    #include <iostream>#include <vector>#include <string> class Assoc {    struct Pair ...

  7. 10.Flask-上下文

    1.1.local线程隔离对象 不用local对象的情况 from threading import Thread request = ' class MyThread(Thread): def ru ...

  8. struts2框架搭建(一)

    struts2是一个基于mvc的web应用框架.struts2本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器层(Controller)来建立模型与视图的数据交互. str ...

  9. js---html元素操作

    思路:创给节点添加一个元素:步骤: 1:创建元素节点 2:创建文本节点 3:将该文本添加到元素上 4:将该元素追加到其他元素上 appendChild() 方法,将新元素作为父元素的最后一个子元素进行 ...

  10. 安卓使用JNI-NDK

    详细配置,参考链接:http://www.jb51.net/softjc/115204.html 一  .为什么使用NDK 1.代码的保护.由于apk的java层代码很容易被反编译,而C/C++库反汇 ...