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

四个字:先进先出

六个字:屁股进,脑袋出

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

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. https=http+ssl

    TLS/SSL中使用了非对称加密,对称加密以及HASH算法.握手过程的具体描述如下: 浏览器将自己支持的一套加密规则发送给网站. 网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式 ...

  2. [19/10/13-星期日] Python中的函数

    一.函数 # 第五章 函数 ## 函数简介(function) - 函数也是一个对象 - 对象是内存中专门用来存储数据的一块区域 - 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行 ...

  3. 基类子类在Qt信号量机制下的思考

    背景知识: 基类 superClass class superClass { public: superClass() { std::string m = "superClass() &qu ...

  4. 图——图的Dijkstra法最短路径实现

    1,最短路径的概念: 1,从有向图中某一顶点(起始顶点)到达另一顶点(终止顶点)的路径中,其权值之和最小的路径: 2,问题的提法: 1,给定一个带权有向图 G 与起始顶点 v,求从 v 到 G 中其它 ...

  5. 五、JVM — 类加载器

    回顾一下类加载过程 类加载器总结 双亲委派模型 双亲委派模型介绍 双亲委派模型实现源码分析 双亲委派模型的好处 如果我们不想要双亲委派模型怎么办? 自定义类加载器 推荐 回顾一下类加载过程 类加载过程 ...

  6. 剑指offer-python-回溯法-矩阵中的路径

    这个系列主要详细记录代码详解的过程. 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格 ...

  7. django学习笔记(四)

    1.请求周期 url> 路由 > 函数或类 > 返回字符串或者模板语言? Form表单提交: 提交 -> url > 函数或类中的方法 - .... HttpRespon ...

  8. struts2_对Map进行双层迭代

    转自:struts2_对Map进行双层迭代 //后台数据 public String execute() throws Exception { Map<String, List<Produ ...

  9. react搭建

    https://juejin.im/post/5b4de4496fb9a04fc226a7af

  10. 奇葩的狐火浏览器border属性

    今天接到一个bug任务,客户反映火狐浏览器访问时某个商品楼层不显示商品.我立即打开我的火狐浏览器发现没有复现这个bug,后来经过一番折腾,才发现火狐浏览器缩放到90%时,商品楼层果然就消失了,而且每台 ...