使用java语言实现一个队列(两种实现比较)(数据结构)
一.什么是队列,换句话说,队列主要特征是什么?
四个字:先进先出
六个字:屁股进,脑袋出
脑补个场景:日常排队买饭,新来的排在后面,前面打完饭的走人,这就是队列;
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语言实现一个队列(两种实现比较)(数据结构)的更多相关文章
- JAVA 集合 List 分组的两种方法
CSDN日报20170219--<程序员的沟通之痛> [技术直播]揭开人工智能神秘的面纱 程序员1月书讯 云端应用征文大赛,秀绝招,赢无人机! JAVA 集合 List 分组的两种方法 2 ...
- 使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网)
使用Java语言编写一个五子棋UI界面并实现网络对战功能(非局域网) 一,前期准备 1,Java IDE(Eclipse)与JDK的安装与配置jdk-15.0.1-免配置路径版提取码:earu免安装版 ...
- java中数组复制的两种方式
在java中数组复制有两种方式: 一:System.arraycopy(原数组,开始copy的下标,存放copy内容的数组,开始存放的下标,需要copy的长度); 这个方法需要先创建一个空的存放cop ...
- Java中Compareable和Comparator两种比较器的区别
Java中Compareable和Comparator两种比较器的区别 参考原文链接:https://www.cnblogs.com/ldy-blogs/p/8488138.html 1.引言 在ja ...
- Java中HashMap遍历的两种方式
Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...
- java动态获取WebService的两种方式(复杂参数类型)
java动态获取WebService的两种方式(复杂参数类型) 第一种: @Override public OrderSearchListRes searchOrderList(Order_Fligh ...
- 一个label两种颜色,一个label两种字体
-(void)addLabel{ UILabel *label = [[UILabel alloc]init]; label.backgroundColor = [UIColor grayColor] ...
- Java使用SFTP和FTP两种连接方式实现对服务器的上传下载 【我改】
[]如何区分是需要使用SFTP还是FTP? []我觉得: 1.看是否已知私钥. SFTP 和 FTP 最主要的区别就是 SFTP 有私钥,也就是在创建连接对象时,SFTP 除了用户名和密码外还需要知道 ...
- java字符串大小写转换的两种方法
转载自:飞扬青春sina blogjava字符串大小写转换的两种方法 import java.io..* public class convertToPrintString { pu ...
随机推荐
- Java json框架简介
Gson,FastJson,Jackson,Json-lib性能比较 https://www.xncoding.com/2018/01/09/java/jsons.html 结论:FastJson虽然 ...
- Linux rsync 远程同步部署篇
rsync官网: www.samba.org/ftp/rsync.html端口:873上机实战系列项目100台规模集群全网数据备份解决方案3.本项目提供免费实战讲解视频:Linux集群全网服务器数据备 ...
- 如何在ubuntu上安装 搜狗输入法(已经成功)
转自:https://blog.csdn.net/qq_37589838/article/details/81208409 本文链接:https://blog.csdn.net/qq_37589838 ...
- 使用git命令删除branch
使用git删除server上的一个branch注意事项: 1. 使用命令:git push origin –delete 分支名 (分支名称需要去掉origin,如果有), git branch ...
- 题解 CF1119A 【Ilya and a Colorful Walk】
此题就是:给你一个数组,让你找出两个不同的元素,并让它们的下标差距最大. 思路:从2到n,如果与1不同,记录距离,与原数比较,取大. 从1到n-1,如果与n不同,记录距离,与原数比较,取大. AC代码 ...
- 使用Docker部署Spring-Boot+Vue博客系统
在今年年初的时候,完成了自己的个Fame博客系统的实现,当时也做了一篇博文Spring-boot+Vue = Fame 写blog的一次小结作为记录和介绍.从完成实现到现在,也断断续续的根据实际的使用 ...
- 【React -- 4/100】 生命周期
生命周期 概述 意义:组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能.分析组件错误原因等 组件的生命周期: 组件从被创建到挂载到页面中运行,再到组件不在时卸载的过程 生命周期的每个阶段总 ...
- 内存缓存的使用Demo
使用缓存的目的是为了使用的应用程序能更快速的响应用户输入,是程序高效的运行.有时候我们需要将远程web服务器获取的数据缓存起来,减少对同一个url多次请求. 内存缓存我们可以使用sdk中的NSURLC ...
- Linux 设置定时清除buff/cache的脚本
Linux 设置定时清除buff/cache的脚本 查看内存缓存状态 [root@heyong ~]# free -m total used free shared buff/cache availa ...
- python socket--TCP解决粘包的方法
1.为什么会出现粘包?? 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意注意: res=subprocess.Popen(cmd.d ...