我理解的数据结构(三)—— 队列(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. java 效率编程 的一些小知识点

    1.在程序中若出现字符串连接的情况.请使用StringBuffer取代String,这样能够降低多次创建String以及垃圾回收所带来的内存消耗 2.尽量使用局部变量. 调用方法时传递的參数以及调用中 ...

  2. 数据结构之---C语言实现最短路径之Dijkstra(迪杰斯特拉)算法

    此处共同拥有两段代码: 一. 这段代码比較全面,当中參考了github上的相关源代码. 能够说功能强大. //Dijkstra(迪杰斯特拉算法) #include <stdio.h> #i ...

  3. Android实战简易教程-第十五枪(实现ListView中Button点击事件监听)

    1.main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" x ...

  4. oc42--引用计数器

    /* main.m 堆里面的内存释放是根据引用计数器,所以就是操作引用计数器. 创建一个对象,对象里面就有一个引用计数器,有多少指针指向它. 引用计数器为0就释放.任何一个对象初始化时就是1,所以 { ...

  5. DCloud-MUI:utils

    ylbtech-DCloud-MUI:utils 1.返回顶部 1.init mui框架将很多功能配置都集中在mui.init方法中,要使用某项功能,只需要在mui.init方法中完成对应参数配置即可 ...

  6. linux下sh语法(转载)

    介绍: 1 开头 程序必须以下面的行开始(必须方在文件的第一行): #!/bin/sh 符号#!用来告诉系统它后面的参数是用来执行该文件的程序. 在这个例子中我们使用/bin/sh来执行程序. 当编写 ...

  7. Agri-Net(prim)

    http://poj.org/problem?id=1258 #include<stdio.h> #include<string.h> ; <<; int map[ ...

  8. WebService开发-CXF

    Web Service 开发方式 Apache CXF 一.关于Apache CXF 在网址http://cxf.apache.org/可以查看到关于Apache CXF的下载及文档介绍,这里不再多做 ...

  9. mybatis 传map参数

    第一步在你的mapper写上: List<WeixinUserLocationList> findweixinUserLocations(@Param("params" ...

  10. Flutter GitLab 客户端

    F4Lab Flutter for GitLab. 欢迎参加一起完成