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

四个字:先进先出

六个字:屁股进,脑袋出

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

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. 配置NAT

    NAT是将IP数据报文报头中的IP地址转换为另-一个IP地址的过程,主要用于实现内部网络(私有IP地址)访问外部网络(公有IP地址)的功能.NAT有3种类型:静态NAT.动态地址NAT以及网络地址端口 ...

  2. python 序列解包(解压缩)

    序列解包(解压缩) 所学的解压缩 如果我们给出一个列表,我们需要一次性取出多个值,我们是不是可以用下面的方式实现呢? name_list = ['nick', 'egon', 'jason'] x = ...

  3. Neo4j清空所有数据

    两种方法: 一.用下列 Cypher 语句: match (n) detach delete n 二. 1.停掉服务: 2.删除 graph.db 目录: 3.重启服务. 原文地址:http://ne ...

  4. git error: failed to push some refs to 'git@github.com:xxx/xxx.git'

    本地仓库中和远程仓库不一致,缺少readme.md文件 解决方式参见:https://blog.csdn.net/qq_37281252/article/details/79044798

  5. MFC- 网络编程

    一.MFC网络编程 a)CAsyncSocket用于异步非阻塞类,用UDP通信: b)CAsyncSocket的子类(派生类):Csocket同步阻塞类,用于TCP通信: c)通信前,必须调用AfxS ...

  6. Hadoop本地模式搭建

    官方文档,不同版本修改url地址中的数字即可 http://hadoop.apache.org/docs/r2.7.2/hadoop-project-dist/hadoop-common/Single ...

  7. easyUI相关文件的引入

    引入以下内容: <head> <meta http-equiv="Content-Type" content="text/html; charset=u ...

  8. 分分钟轻松搞定IBM系列 RAID5搭建

    分分钟轻松搞定IBM系列 RAID5搭建 按照 以下图片步骤一步步可轻松完成IBM服务器RAID1.5.10等的搭建. 此例是以RAID5为例,RAID1和10可举一反三.

  9. CRMEasy知识库点击无法弹出窗体问题

    丢失控件   MSDATLST.OCX 将此控件放在路径下    C:\Windows\System32 并进行注册,具体方法为: 打开控件方式选择   C:\Windows\System32\reg ...

  10. TreeView详细用法

    Treeview用于显示按照树形结构进行组织的数据.          Treeview控件中一个树形图由节点(TreeNode)和连接线组成.TtreeNode是TTreeview的基本组成单元. ...