深入浅出ArrayDeque的设计和实现

深入浅出ArrayDeque的设计和实现说在前面 本篇文章不适合小白 需要先了解循环队列的数组实现 一 避轻就重 抓住核心 ArrayDeque 容器类可能大家平时用得很少 但是其代码的设计和实现真比我们平常经常用的 ArrayList Stack Vector 要深刻的多 ArrayDeque 容器类的方法里有许多

大家好,我是讯享网,很高兴认识大家。

说在前面,本篇文章不适合小白,需要先了解循环队列的数组实现。

一、避轻就重,抓住核心

ArrayDeque容器类可能大家平时用得很少,但是其代码的设计和实现真比我们平常经常用的ArrayList,Stack(Vector)要深刻的多!ArrayDeque容器类的方法里有许多,但是核心的方法其实就4个,下面我们会具体介绍,但是要稍有一些耐心,因为ArrayDeque涉及到的知识点还蛮多的。

二、铺垫

ArrayDeque和LinkedList是Deque的两个通用实现,并且官方更推荐使用AarryDeque用作栈和队列。因此,要讲ArrayDeque,首先要讲Deque接口。Deque的含义是“double ended queue”,即双端队列,它既可以当作栈使用,也可以当作队列使用。
下表列出了Deque与Queue相对应的接口:
在这里插入图片描述
讯享网
下表列出了Deque与Stack对应的接口:
在这里插入图片描述
上述提到的方法,其实核心的就是我框出来的那4个,其他方法要么是调用要么就是被调用,内在逻辑在addFirst(),addLast(),removeFirst,removeLast中。

为什么选用这四个作为代表呢?因为这四个方法名起得好,具体原因后面再说,先来说ArrayDeque如何使用上面的函数实现队列的,到这儿,大家可以对上面应该有了个印象,下面我们重新开始一段故事。

三、核心–循环队列的数组实现

ArrayDeque的核心如果用一句话概括,就是循环队列的数组实现,只不过加了双向增删数据。
那么,首先,我们得先知道,循环队列是如何用数组实现的。

3.1 循环队列
/* 数组实现的双端队列:本质上是循环队列 head指向队首元素,tail指向队尾元素的下一空位 */ public class ArrayBasedCircularQueue { 
    private int head=0; private int tail=0; protected int[] array; //循环队列的大小要比实际的要大1 public ArrayBasedCircularQueue(int capacity){ 
    array=new int[capacity+1]; } //入队 public void enQueue(int item){ 
    //判断是否队满 if((tail+1)%(array.length)==head){ 
    System.out.println("The queue is Full!"); return; } array[tail]=item; tail=(tail+1)%(array.length); } //出队 public int deQueue(){ 
    //判断是否队空 if(tail==head){ 
    System.out.println("The queue is Empty!"); return -1; } int temp=head; head=(head+1)%(array.length); return array[temp]; } //打印队列所有元素 public void print(){ 
    for (int i = head; i % array.length != tail; i = (i + 1) % array.length){ 
    System.out.println(array[i]); } } public static void main(String[] args) { 
    ArrayBasedCircularQueue queue=new ArrayBasedCircularQueue(3); queue.enQueue(1); queue.enQueue(2); queue.enQueue(3); //队满 queue.enQueue(4); queue.print(); //出队 System.out.println("出队:"); queue.deQueue(); queue.print(); //入队 System.out.println("入队:"); queue.enQueue(4); queue.print(); //出队 queue.deQueue(); //入队 System.out.println("入队:"); queue.enQueue(5); queue.print(); } } 

讯享网

学习编程,敲代码是唯一的学习方法。上述代码,希望你能敲一遍。对于上面代码,不知你没有发现一个问题,这个问题就是“循环队列的大小为什么要比实际的要大1。”,也就是说“为什么循环队列总有一个位置是空着的。”,这个原因,我理解是由于“head指向队首元素,tail指向队尾元素的下一空位”,那么为什么“tail要指向队尾元素的下一空位”,而不是“指向队尾元素呢?” ,这里,tail要指向队尾元素的下一空位不是我故意这么设计的,JAVA容器类也是这么实现的,原因是什么呢?大家感兴趣,可以好好琢磨琢磨。

3.2 循环队列的双向增删

上面,我们实现的循环队列,如果把循环队列看成是一个圆,我们只是实现了顺时针的增删元素,顺时针的增删元素,enQueue()deQueue()方法,其实就对应着addLast()removeFirst()(顾命思义一下,动动脑筋,不难想到),对于ArrayDeque这种双端队列,我们还需要实现逆时针的增删元素,那就是addFirst()removeLast()

讯享网/* 数组实现的双端队列:本质上是循环队列 head指向队首元素,tail指向队尾元素的下一位 */ public class ArrayBasedDeque { 
    private int head=0; private int tail=0; protected int[] array; //循环队列的大小要比实际的要大1 public ArrayBasedDeque(int capacity){ 
    array=new int[capacity+1]; } //入队:从前往后 --> /* 这在ArrayBasedDeque里称之为addLast(); */ public void enQueue(int item){ 
    //判断是否队满 if((tail+1)%(array.length)==head){ 
    System.out.println("The queue is Full!"); return; } array[tail]=item; tail=(tail+1)%(array.length); } //入队:从后往前 <-- public void AddFirst(int item){ 
    if((tail+1)%(array.length)==head){ 
    System.out.println("The queue is Full!"); return; } array[head=(head - 1) & (array.length - 1)]=item; } //出队:先进先出 /* 这在ArrayBasedDeque里称之为removeFirst(); */ public int deQueue(){ 
    //判断是否队空 if(tail==head){ 
    System.out.println("The queue is Empty!"); return -1; } int temp=head; head=(head+1)%(array.length); return array[temp]; } //出队:先进先出 public int removeLast(){ 
    if(tail==head){ 
    System.out.println("The queue is Empty!"); return -1; } return array[tail=(tail-1)& (array.length - 1)]; } //打印队列所有元素 public void print(){ 
    for (int i = head; i % array.length != tail; i = (i + 1) % array.length){ 
    System.out.println(array[i]); } } } 

上述代码,还是得你敲一遍。我留一个问题,看你是否掌握了,addLast()、removeFirst()实现的队列,和AddFirst(),removeLast()实现的队列在存储元素时,他们在数组中的顺序是什么样的?

所以,到这,如果你弄懂了循环队列的数组实现,并且是如何支持双向增删数据,那么你应该不难想出,怎么用addFirst(),addLast(),removeFirst,removeLast这四个方法来实现出栈,这需要你自己动手。

小讯
上一篇 2025-03-28 13:51
下一篇 2025-02-19 15:27

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/57193.html