头图

深入剖析(JDK)ArrayQueue源码

深入剖析(JDK)ArrayQueue源码

前言

在本篇文章当中主要给大家介绍一个比较简单的JDK为我们提供的容器ArrayQueue,这个容器主要是用数组实现的一个单向队列,整体的结构相对其他容器来说就比较简单了。

ArrayQueue内部实现

在谈ArrayQueue的内部实现之前我们先来看一个ArrayQueue的使用例子:

public void testQueue() {
    ArrayQueue<Integer> queue = new ArrayQueue<>(10);
    queue.add(1);
    queue.add(2);
    queue.add(3);
    queue.add(4);
    System.out.println(queue);
    queue.remove(0); // 这个参数只能为0 表示删除队列当中第一个元素,也就是队头元素
    System.out.println(queue);
    queue.remove(0);
    System.out.println(queue);
}
// 输出结果
[1, 2, 3, 4]
[2, 3, 4]
[3, 4]

首先ArrayQueue内部是由循环数组实现的,可能保证增加和删除数据的时间复杂度都是$O(1)$,不像ArrayList删除数据的时间复杂度为$O(n)$。在ArrayQueue内部有两个整型数据headtail,这两个的作用主要是指向队列的头部和尾部,它的初始状态在内存当中的布局如下图所示:

因为是初始状态headtail的值都等于0,指向数组当中第一个数据。现在我们向ArrayQueue内部加入5个数据,那么他的内存布局将如下图所示:

现在我们删除4个数据,那么上图经过4次删除操作之后,ArrayQueue内部数据布局如下:

在上面的状态下,我们继续加入8个数据,那么布局情况如下:

我们知道上图在加入数据的时候不仅将数组后半部分的空间使用完了,而且可以继续使用前半部分没有使用过的空间,也就是说在ArrayQueue内部实现了一个循环使用的过程。

ArrayQueue源码剖析

构造函数

public ArrayQueue(int capacity) {
    this.capacity = capacity + 1;
    this.queue = newArray(capacity + 1);
    this.head = 0;
    this.tail = 0;
}

@SuppressWarnings("unchecked")
private T[] newArray(int size) {
    return (T[]) new Object[size];
}

上面的构造函数的代码比较容易理解,主要就是根据用户输入的数组空间长度去申请数组,不过他具体在申请数组的时候会多申请一个空间。

add函数

public boolean add(T o) {
    queue[tail] = o;
    // 循环使用数组
    int newtail = (tail + 1) % capacity;
    if (newtail == head)
        throw new IndexOutOfBoundsException("Queue full");
    tail = newtail;
    return true; // we did add something
}

上面的代码也相对比较容易看懂,在上文当中我们已经提到了ArrayQueue可以循环将数据加入到数组当中去,这一点在上面的代码当中也有所体现。

remove函数

public T remove(int i) {
    if (i != 0)
        throw new IllegalArgumentException("Can only remove head of queue");
    if (head == tail)
        throw new IndexOutOfBoundsException("Queue empty");
    T removed = queue[head];
    queue[head] = null;
    head = (head + 1) % capacity;
    return removed;
}

从上面的代码当中可以看出,在remove函数当中我们必须传递参数0,否则会抛出异常。而在这个函数当中我们只会删除当前head下标所在位置的数据,然后将head的值进行循环加1操作。

get函数

public T get(int i) {
    int size = size();
    if (i < 0 || i >= size) {
        final String msg = "Index " + i + ", queue size " + size;
        throw new IndexOutOfBoundsException(msg);
    }
    int index = (head + i) % capacity;
    return queue[index];
}

get函数的参数表示得到第i个数据,这个第i个数据并不是数组位置的第i个数据,而是距离head位置为i的位置的数据,了解这一点,上面的代码是很容易理解的。

resize函数

public void resize(int newcapacity) {
    int size = size();
    if (newcapacity < size)
        throw new IndexOutOfBoundsException("Resizing would lose data");
    newcapacity++;
    if (newcapacity == this.capacity)
        return;
    T[] newqueue = newArray(newcapacity);
    for (int i = 0; i < size; i++)
        newqueue[i] = get(i);
    this.capacity = newcapacity;
    this.queue = newqueue;
    this.head = 0;
    this.tail = size;
}

resize函数当中首先申请新长度的数组空间,然后将原数组的数据一个一个的拷贝到新的数组当中,注意在这个拷贝的过程当中,重新更新了headtail,而且并不是简单的数组拷贝,因为在之前的操作当中head可能已经不是了0,因此新的拷贝需要我们一个一个的从就数组拿出来,让后放到新数组当中。下图可以很直观的看出这个过程:

总结

在本篇文章当中主要给大家介绍了ArrayQueue的内部实现过程和原理,并且看了ArrayQueue的源代码,有图的辅助整个阅读的过程应该是比较清晰的,ArrayQueue也是一个比较简单的容器,JDK对他的实现也比较简单。

以上就是本文所有的内容了,希望大家有所收获,我是LeHung,我们下期再见!!!(记得点赞收藏哦!)


更多精彩内容合集可访问项目:https://github.com/Chang-LeHu...

关注公众号:一无是处的研究僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识。

分享Java Python 大数据 各平台账号同名!!!

23 声望
0 粉丝
0 条评论
推荐阅读
深入理解 python 虚拟机:pyc 文件结构
在本篇文章当中主要给大家介绍一下 .py 文件在被编译之后对应的 pyc 文件结构,pyc 文件当中的一个核心内容就是 python 字节码。

一无是处的研究僧阅读 221

封面图
数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 5.4k

openKylin 0.9.5版本正式发布,加速国产操作系统自主创新进程!
2023年1月12日,中国桌面操作系统根社区openKylin(开放麒麟)正式发布openKylin 0.9.5操作系统版本。此版本充分适应5G时代需求,打通平板,PC等设备,实现多端融合,弥补了国产操作系统的短板,有效推动国产操作...

openKylin6阅读 8k

封面图
不会数学的程序员,只能走到初级开发工程师!
在我还是初级程序员时,每天也都粘贴着代码和包装着接口。那个阶段并没有意识到数学能在编程中起到什么作用,就算学了数学的部分知识,也没法用到编程中。但后来随着编程越来越久,逐步接手核心代码块开发时候,...

小傅哥3阅读 998

封面图
杨辉三角的5个特性,一个比一个牛皮!
杨辉三角按照杨辉于1261年所编写的《详解九章算法》一书,里面有一张图片,介绍此种算法来自于另外一个数学家贾宪所编写的《释锁算书》一书,但这本书早已失传无从考证。但可以肯定的是这一图形的发现我国不迟于1...

小傅哥3阅读 1.9k

stackoverflow 提问:“计算两个整数的最小公倍数的最有效方法是什么?”
作者:小傅哥博客:[链接]源码:[链接]沉淀、分享、成长,让自己和他人都能有所收获!😄一、前言嘿,小傅哥怎么突然讲到最大公约数了?这么想你肯定是没有好好阅读前面章节中小傅哥讲到的RSA算法,对于与欧拉结果...

小傅哥3阅读 1.8k

封面图
DeepMind 发布强化学习通用算法 DreamerV3,AI 成精自学捡钻石
内容一览:强化学习是多学科领域的交叉产物,其本质是实现自动决策且可做连续决策。本文将介绍 DeepMind 最新研发成果:扩大强化学习应用范围的通用算法 DreamerV3。关键词:强化学习 DeepMind 通用算法

超神经HyperAI1阅读 949

封面图

分享Java Python 大数据 各平台账号同名!!!

23 声望
0 粉丝
宣传栏