一、前言
1.1 队列的概念
通过之前的集合框架图示可以看到队列(Queue)是一个接口,只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,进行插入操作的一端称为队尾,进行删除操作的一端称为队头
1.2 队列的特点
队列具有先进先出的特点。
1.3 队列的操作
与上篇博客介绍的栈一样,队列相当于对线性表的功能进行了限制.基本操作就是以下三种:
1.入队列(从队尾插入元素)
2.出队列(删除队首的元素)
3.取队首元素(获取到队首位置的元素的值)
1.4 队列的变种
1.普通的队列:先出先进的规则
2.优先出队列:出队列的顺序和入队列的顺序不一样,每次出队列的元素都是优先级最高的元素(本质上是一个堆)
3.消息队列:也不是严格的先进先出,而是按照"类型"来获取元素(业务类型)(实际工作中会用到很多的"消息队列服务器")
4.阻塞队列:当队列为空的时候,出队列操作就会阻塞;当队列为满的时候,入队列操作就会阻塞(代码执行到某个地方就不往下走了,一直等待)
5.无锁队列:线程安全的队列,不是通过锁来实现线程安全 比较高效 CAS操作来实现的
二、队列的实现
2.1 基于数组实现队列
public class MyQueueByArrayList {
private int[] array=new int[100];
//[head,tail)初始情况下队列中应该是没有元素的
private int head=0;
private int tail=0;
private int size=0;
//如果插入成功返回true
//如果插入失败返回false
public boolean offer(int value){
if(size==array.length){
return false;
}
array[tail]=value;
tail++;
if(tail>=array.length){
tail=0;
}
//tail=tail%array.length
size++;
return true;
}
public Integer poll(){
if(size==0){
//队列为空,出队列失败
return null;
}
//队列非空,返回head位置的元素,同时head++ 删除该元素
int ret=array[head];
head++;
if(head>=array.length){
head=0;
}
size--;
return ret;
}
public Integer peek(){
if(size==0){
return null;
}
return array[head];
}
public static void main(String[] args) {
MyQueueByArrayList queue=new MyQueueByArrayList();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
while(true){
Integer cur=queue.poll();
if(cur==null){
break;
}
System.out.println(cur);
}
}
}
2.2 基于链表实现队列
链表的方式来实现更简单一些,链表的尾部作为队尾(方便插入元素) 链表头部作为队首(方便删除元素),为了方便的实现尾插,多搞一个引用指向链表的尾部,这里为了方便实现也用到了傀儡结点
public class MyQueueByLinkedList {
static class Node{
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
}
private Node head=new Node(-1);
private Node tail=head;
private int size;//队列中的元素个数
//入队列(链表尾插)
public void offer(int value){
Node newNode=new Node(value);
//核心操作就是这一行代码
tail.next=newNode;
tail=tail.next;
}
//出队列(链表头删)
public Integer poll(){
if(head.next==null){
//队列为空,出队列失败
return null;
}
Node toDelete=head.next;
head.next=toDelete.next;
if(head.next==null){
//此时队列已经为空了.
//让tail指回傀儡结点
tail=head;
}
return toDelete.val;
//不要忘了更新尾部
}
//取队首元素
public Integer peek(){
if(head.next==null){
//空队列
return null;
}
return head.next.val;
}
public static void main(String[] args) {
MyQueueByLinkedList queue=new MyQueueByLinkedList();
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
while(true){
Integer cur=queue.poll();
if(cur==null){
break;
}
System.out.println(cur);
}
}
}
这里就是用两种方式来自己实现队列的全部代码,核心思想就是先进先出
外加一个小tips:
1.链表版本的队列:插入元素无上限,效率更低,需要额外的内存空间保存引用地址
2.数组版本的队列:插入元素有上限,效率更高,不需要额外空间保存引用地址
3.标准库中的队列Queue基于链表实现的,后面在工作中接触到的很有可能是用数组版本实现的