看过笔者前两篇介绍的Java版
数据结构数组
和栈
的盆友,都给予了笔者一致的好评,在这里笔者感谢你们的承认!!!前端
因为本章介绍的数据结构是队列
,在队列的实现上会基于前面写的动态数组
来实现,而队列
又和栈
不管是从特色上和操做上都有相似之处,因此在这里对这两种数据结构不了解的朋友,能够去看一下笔者前两篇文章介绍的数据结构数组
和栈
,这里笔者把连接贴出来(看过的盆友能够跳过此步骤...)java
队列是一种特殊的线性表,它只容许在表的前端(front)进行删除操做,而在表的后端(rear)进行插入操做,和栈同样,队列是一种操做受限制的线性表。进行插入操做的端称为队尾,进行删除操做的端称为队头。git
队列的操做方式和栈
相似,惟一的区别在于队列只容许新数据在后端(rear)进行添加。github
以前在介绍栈的时候,经过示意图来帮助你们了解什么是栈;这里,我仍采用示意图形式向你们演示队列经常使用的两个操做:入队操做
和出队操做
。后端
队列入队操做数组
这里咱们能够形象地想成咱们到银行办理业务排队的场景,如今A、B、C三个元素分别到银行柜台排成一条队办理业务(咱们都是文明的孩纸,总不能插队O(∩_∩)O哈!),依次排队的元素是:A、B、C。数据结构
队列出队操做ide
当元素A
办理完业务时,当前是元素A
先离开队列,而后是元素B
,最后是元素C
性能
咱们时刻要牢记队列,入队是从
队尾
一端进行入队,出队是从队首
一端进行出队,是一种:先进先出的数据结构。测试
本文会介绍队列的两张实现方式,一种是数组队列,另一种是循环队列,考虑篇幅长度缘由,本篇咱们暂时只介绍数组队列,循环队列放在下一篇介绍。
如今咱们声明一个数组的长度(capacity=3),元素个数为(size=0)的int类型数组的空队列,在这里,假设对队列的队首
为数组的左侧
,队尾
为数组的右侧
,示意图以下:
如今若是咱们有四个元素:A、B、C、D要入队
元素A
入队
元素A
已经入队了,如今开始元素B
入队
元素A
和元素B
已经入队了,如今开始元素C
入队
元素A
、B
和C
已经分别入队了,如今若是咱们要开始元素D
入队,根据咱们以前定义的动态数组的特性,若是元素D
进行入队操做,会发现此时咱们的数组已经满了,这时候数组会自动地扩容
(扩容的原理:新建一个容量是原数组容量两倍的数组,把原数组中的元素依次拷贝到新的数组中,最后引用指向新的数组)的原来的两倍(具体扩容多少,盆友能够自行设置)示意图以下:
到这里咱们已经完成了元素:A、B、C、D的入队操做了,如今咱们来看一下,它们的出队操做,根据队列的特性,队列是一种先进先出
的数据结构,以前入队操做顺序依次是:A->B->C->D
,那么出队操做顺序仍然是:A->B->C->D
如今咱们来看一下元素A
和元素B
出队后的示意图:
元素C
和D
的出队原理和元素A
出队的原理同样,直至所有出队完成,变成空队列
在元素出队的过程当中,相应地也会进行缩容操做,以前笔者这边定义,当数组中元素的个数(size)等于数组容量(capacity)的一半时,数组会进行缩容操做,这也正是动态数组的特色。
了解了数组队列的底层原理以后,接下来咱们用代码来实现一下(建议盆友,在看以前,本身能够尝试写一下,而后在看,这样印象可能会比较深入O(∩_∩)O哈!)
void enqueue(E e);
复制代码
E dequeue();
复制代码
E getFront();
复制代码
int getSize();
复制代码
boolean isEmpty();
复制代码
接口定义 :Queue
public interface Queue<E> {
/** * 入队 * * @param e */
void enqueue(E e);
/** * 出队 * * @return */
E dequeue();
/** * 获取队首元素 * * @return */
E getFront();
/** * 获取队列中元素的个数 * * @return */
int getSize();
/** * 判断队列是否为空 * * @return */
boolean isEmpty();
}
复制代码
DynamicArrayQueue 类实现接口 Queue
public class DynamicArrayQueue<E> implements Queue<E> {
/** * 用数组存放队列中元素的个数 */
private DynamicArray<E> dynamicArray;
/** * 指定容量,初始化队列 * * @param capacity */
public DynamicArrayQueue(int capacity) {
dynamicArray = new DynamicArray<>(capacity);
}
/** * 默认容量,初始化队列 */
public DynamicArrayQueue() {
dynamicArray = new DynamicArray<>();
}
@Override
public void enqueue(E e) {
dynamicArray.addLast(e);
}
@Override
public E dequeue() {
return dynamicArray.removeFirst();
}
@Override
public E getFront() {
return dynamicArray.getFirst();
}
@Override
public int getSize() {
return dynamicArray.getSize();
}
@Override
public boolean isEmpty() {
return dynamicArray.isEmpty();
}
@Override
public String toString() {
return "DynamicArrayQueue{" +
"【队首】dynamicArray=" + dynamicArray + "}【队尾】";
}
}
复制代码
测试类: DynamicArrayQueueTest
public class DynamicArrayQueueTest {
@Test
public void testArrayQueue() {
// 指定容量(capacity=6)初始化队列
DynamicArrayQueue<String> dynamicArrayQueue = new DynamicArrayQueue(3);
System.out.println("初始队列:" + dynamicArrayQueue);
// 准备入队元素
List<String> enQueueElements = Arrays.asList("A", "B", "C");
// 元素入队
enQueueElements.forEach(x -> dynamicArrayQueue.enqueue(x));
System.out.println("元素A、B、C入队:" + dynamicArrayQueue);
// 此时若是又有一个元素D入队,会发生扩容操做 (size == capacity)进行扩容
dynamicArrayQueue.enqueue("D");
System.out.println("元素D入队,发生扩容:" + dynamicArrayQueue);
// 元素A出队,会发生缩容操做(size == capacity / 2)进行缩容
dynamicArrayQueue.dequeue();
System.out.println("元素A出队,发生缩容:" + dynamicArrayQueue);
// 元素B出队
dynamicArrayQueue.dequeue();
System.out.println("元素B出队:" + dynamicArrayQueue);
}
}
复制代码
运行结果
初始队列:DynamicArrayQueue{【队首】dynamicArray=DynamicArray{data=[null, null, null], size=0,capacity=3}}【队尾】
元素A、B、C入队:DynamicArrayQueue{【队首】dynamicArray=DynamicArray{data=[A, B, C], size=3,capacity=3}}【队尾】
元素D入队,发生扩容:DynamicArrayQueue{【队首】dynamicArray=DynamicArray{data=[A, B, C, D, null, null], size=4,capacity=6}}【队尾】
元素A出队,发生缩容:DynamicArrayQueue{【队首】dynamicArray=DynamicArray{data=[B, C, D], size=3,capacity=3}}【队尾】
元素B出队:DynamicArrayQueue{【队首】dynamicArray=DynamicArray{data=[C, D, null], size=2,capacity=3}}【队尾】
复制代码
细心的盆友,会发现,由于队列的底层是数组来实现的,队列的出队操做实际上就是:删除数组中的第一个元素,后面的全部元素都要往前面挪一位;其实这样性能是比较低下的,时间复杂度是O(n)级别的。
咱们想若是元素进行出队操做后,可否不挪动后面的元素,还能维持队列的特性,这样问题不就解决了吗?盆友能够自行思考一下。
完整版代码GitHub仓库地址:Java版数据结构-队列(数组队列) 欢迎你们【关注】和【Star】
本篇完成的数组队列是基于以前【Java版-数据结构-数组】动态数组来实现的,下一篇笔者会给你们介绍用循环队列来解决数组队列带来的性能问题。接下来,笔者还会一一的实现其它常见的数组结构。
持续更新中,欢迎你们关注公众号:小白程序之路(whiteontheroad),第一时间获取最新信息!!!