一.什么是队列,换句话说,队列主要特征是什么?

四个字:先进先出

六个字:屁股进,脑袋出

脑补个场景:日常排队买饭,新来的排在后面,前面打完饭的走人,这就是队列;

OK,思考一个问题,我为什么写了两种实现,它们的区别是什么,哪个性能更好一些?

我觉得学习一定要带着问题来学习;

二.队列的两种实现

1.数组队列

数组队列比较简单,基于之前写的动态数组所实现的,基本方法都是根据队列特性从而选择性的调用动态数组的方法来实现的。

public class ArrayQueue<E> implements Queue<E> {
private Array<E> array; public ArrayQueue (int catacity) {
array = new Array<E>(catacity);
} public ArrayQueue () {
array = new Array<E>();
}
//查看队列容量
public int catacity () {
return array.getCapacity();
}
//获取队列中元素个数
@Override
public int getSize() {
return array.getSize();
}
//判断队列是否为空
@Override
public boolean isEmpty() {
return array.isEmpty();
}
//入队 时间复杂度:O(1)
@Override
public void enqueue(E e) {
array.addLast(e);
}
//出队 时间复杂度:O(n)
@Override
public E dequeue() {
return array.removeFirst();
}
//查看队首元素 时间复杂度: O(1)
@Override
public E getFront() {
return array.getFirst();
}
@Override
public String toString () {
StringBuilder res = new StringBuilder();
res.append("Queue");
res.append("front [");
for (int i = 0; i < getSize(); i++) {
res.append(array.getByIndex(i));
if (i != array.getSize() - 1) {
res.append(",");
}
}
res.append("] tail");
return res.toString();
} public static void main (String[] args) {
ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
for(int i = 0; i < 10; i++) {
arrayQueue.enqueue(i);
System.out.println(arrayQueue);
if (i % 3 == 2) {
System.out.println(arrayQueue);
}
}
}
}

2.循环队列

什么是循环队列?用图来说明

(1)队首在0位置,队尾在4位置,队列里面有4个元素

(2)此时,我进行两次出队操作,队首位置为2,队首前面空了两个空间。

 (3)我再进行三次入队操作,其中一个元素插到了数组的前面。

循环队列:就是当数组末端没有位置时,新的入队元素则插到数组前面空余的空间中,避免了空间的浪费,可以把整个数组想象成一个环状。

代码实现:

public class LoopQueue<E> implements Queue<E> {

    private E[] data;
//队首
private int front;
//队尾
private int tail;
//队列中元素个数
private int size; public LoopQueue (int catacity) {
//实际开辟的容量比用户定义的容量大一位
data = (E[])new Object[catacity + 1];
front = 0;
tail = 0;
size = 0;
} public LoopQueue () {
this(10);
}
//获取队列容量
public int getCapacity () {
return data.length - 1;
}
//获取队列元素个数
@Override
public int getSize() {
return size;
}

当front == tail 时,定义队列为空

//队列是否为空
@Override
public boolean isEmpty() {
return tail == front;
}
//入队
@Override
public void enqueue(E e) {
//判断数组空间满没满,满了的话进行扩容
if ((tail + 1) % data.length == front) {
resize(getCapacity() * 2);
} data[tail] = e;
tail = (tail + 1) % data.length;
size ++;
}
//出队
@Override
public E dequeue() {
if (isEmpty()) {
throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
}
E set = data[front];
data[front] = null;
front = (front + 1) % data.length;
size --;
//缩容
if (size == getCapacity() / 4 && getCapacity() / 2 != 0) {
resize(getCapacity()/2);
}
return set;
}
//获取队首元素
@Override
public E getFront() {
if (isEmpty()) {
throw new IllegalArgumentException("Queue is empty.");
}
return data[front];
} //扩容
public void resize (int catacity) {
E[] newArray = (E[])new Object[catacity];
//将旧数组中元素复制到新数组中
for (int i = 0; i < size; i++) {
newArray[i] = data[(i + front) % data.length];
}
data = newArray;
front = 0;
tail = size;
} @Override
public String toString () {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("LoopQueue");
stringBuilder.append("front [");
for (int i = 0; i < size; i++) {
stringBuilder.append(data[(i + front) % data.length]);
if (i != size - 1) {
stringBuilder.append(",");
}
}
stringBuilder.append("] tail");
return stringBuilder.toString();
}

循环队列总结:

三.两种队列的简单比较

分别用数组队列和循环队列,将10万个数,入队再出队;

 public static Double testQueue (Queue<Integer> queue, int opCount) {

        long startTime = System.nanoTime();
Random random = new Random(); for (int i = 0; i < opCount; i++) {
queue.enqueue(random.nextInt(Integer.MAX_VALUE));
}
for (int i = 0; i < opCount; i++) {
queue.dequeue();
} long endTime = System.nanoTime();
return ( endTime - startTime) / 1000000000.0;
} public static void main(String[] args) {
int opCount = 100000;
Queue<Integer> loopQueue = new LoopQueue<>();
Queue<Integer> arrayQueue = new ArrayQueue<>();
System.out.println("ArrayQueue, time1 = " + Main.testQueue(arrayQueue,opCount));
System.out.println("LoopQueue, time2 = " + Main.testQueue(loopQueue,opCount)); //new Main().stack();
}

测试结果:两者差距近200倍。

最后,

浮于表面看千遍,

不如自己思一遍,

希望这篇文章能够对你起到帮助。

使用java语言实现一个队列(两种实现比较)(数据结构)的更多相关文章

  1. JAVA 集合 List 分组的两种方法

    CSDN日报20170219--<程序员的沟通之痛> [技术直播]揭开人工智能神秘的面纱 程序员1月书讯 云端应用征文大赛,秀绝招,赢无人机! JAVA 集合 List 分组的两种方法 2 ...

  2. 使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网)

    使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网) 一,前期准备 1,Java IDE(Eclipse)与JDK的安装与配置jdk-15.0.1-免配置路径版提取码:earu免安装版 ...

  3. java中数组复制的两种方式

    在java中数组复制有两种方式: 一:System.arraycopy(原数组,开始copy的下标,存放copy内容的数组,开始存放的下标,需要copy的长度); 这个方法需要先创建一个空的存放cop ...

  4. Java中Compareable和Comparator两种比较器的区别

    Java中Compareable和Comparator两种比较器的区别 参考原文链接:https://www.cnblogs.com/ldy-blogs/p/8488138.html 1.引言 在ja ...

  5. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

  6. java动态获取WebService的两种方式(复杂参数类型)

    java动态获取WebService的两种方式(复杂参数类型) 第一种: @Override public OrderSearchListRes searchOrderList(Order_Fligh ...

  7. 一个label两种颜色,一个label两种字体

    -(void)addLabel{ UILabel *label = [[UILabel alloc]init]; label.backgroundColor = [UIColor grayColor] ...

  8. Java使用SFTP和FTP两种连接方式实现对服务器的上传下载 【我改】

    []如何区分是需要使用SFTP还是FTP? []我觉得: 1.看是否已知私钥. SFTP 和 FTP 最主要的区别就是 SFTP 有私钥,也就是在创建连接对象时,SFTP 除了用户名和密码外还需要知道 ...

  9. java字符串大小写转换的两种方法

    转载自:飞扬青春sina blogjava字符串大小写转换的两种方法 import java.io..* public class convertToPrintString {          pu ...

随机推荐

  1. java主方法组成分析

    public static void main(String args[]) public :是一种访问权限,主方法是一切的开始点,开始点一定是公共的 static :表示此方法可由类直接调用 voi ...

  2. [19/09/08-星期日] Python的几个概念和语法

    一.表达式.语句.程序.函数 1.表达式 就是一个类似于数学公式的东西 ,比如:10 + 5 8 - 4:表达式一般仅仅用了计算一些结果,不会对程序产生实质性的影响 如果在交互模式中输入一个表达式,解 ...

  3. 2019JS必看面试题

    2019JS必看面试题:https://www.jianshu.com/p/f1f39d5b2a2e 1. javascript的typeof返回哪些数据类型. 答案:string,boolean,n ...

  4. 怎样用adb抓取log?

    在Android客户端的测试过程中,有时候我们会遇到闪退等异常情况.这时我们可以通过adb抓取log,从而给开发提供更多信息. 一.下载ADB.exe     在网上搜索“adb工具包”就可以找到很多 ...

  5. pistat 查看进程状态

    该pidstat命令用于监视当前正在由Linux内核管理的各个任务.对于使用选项-p选择的每个任务,或者如果使用了选项-p ALL,则它将写入Linux内核管理的 每个任务的标准输出活动.不选择任何任 ...

  6. dajngo ORM查询中select_related的作用,博客主题的定制,从数据库中按照年月筛选时间

    1.dajngo ORM查询中select_related的作用 select_related()方法一次性的把数据库关联的对象都查询出来放入对象中,再次查询时就不需要再连接数据库,节省了后面查询数据 ...

  7. ffmpeg 常用命令汇总

    最近工作常用到ffmpeg 做一些视频数据的处理转换等,用来做测试,今天总结了一下,并参考了网上一些部分朋友的经验,一起在这里汇总了一下,有需要的朋友可以收藏测试一下,有问题可以回帖交流. 1.ffm ...

  8. 关于jsp 获得当前绝对路径的方法

    方法1) request.getRequestURL(); 方法2)  request.getScheme()+"://"+request.getServerName()+&quo ...

  9. 树状数组求LIS模板

    如果数组元素较大,需要离散化. #include <iostream> #include <cstdio> #include <cstring> #include ...

  10. vim 修改复制过来的代码缩进

    命令模式下 :1,9<  //1至9行回退一个tab :1,9> //1至9行缩进一个tab 让不可打印字符心事出来::set list