队列
一、队列概述
1.1 队列简介
1.1.1 队列定义
- 队列就是一个先进先出的线性表
- 它允许在表的一端插入数据,在另一端删除元素,插入元素的这一端称之为队尾
1.1.2 队列特性
- 在队尾插入元素,在队首删除元素。
- FIFO(先进先出)
1.1.3 结构
(1) 队头front:
- 删除数据的一端。对于数组,从后面插入更容易,前面插入较困难,所以一般用数组实现的队列队头在前面。(删除直接index游标前进,不超过队尾即可)。而对于链表。插入删除在两头分别进行那么头部(前面)删除尾部插入是最方便的选择
(2) 队尾rear:
- 插入数据的一端,同上,在数组和链表中通常均在尾部位置。
(3) 队长length:
对于顺序队列
对于链式队列
- length需提前创建一个变量来记录,以免靠遍历结点才能获取
1.2 队列分类
1.2.1 数组队列
(1)定义
(2)结构
- 包含一个存储元素的数组
- 整形变量 front 来标记队头位置
- 整形变量 rear 标记队尾位置
1.2.2 链式队列
(1)存储结构
- 底层为链表
- 包含一个指向向队头结点的引用(指针)front,与一个指向向队尾结点的引用(指针)rear
- 表示该队列的长度的整型变量 int length
1.2.3 双向队列
(1)特性
1.2.4 循环队列
(1)循环队列
- 定义
- 循环队列仍是数组实现的,但其中包含两个指针front,rear 指向队头,对尾,在添加队尾元素,与弹出对头元素时,改变front与rear的值,相互追赶,且对两个值进行求余,防止数组越界
(2) 采用循环队列原因
- 如果数组队列如果使用front指针来标识队头元素所在下标,每次出队时,都需要将front++,容易使得数组溢出,数组每一个位置只用一次,利用率极低,即每进行一次出队操作,数组可用空间就减一
![](https://i-blog.csdnimg.cn/blog_migrate/23c16681c38f0dd9c8ecb9eb3a32fa82.png)
- 如果不使用front,每次入队rear++,每次出队时,rear–,则需将后n-1个元素都前移一位,时间复杂度高
(3)操作算法
- 初始化:数组的front和rear都指向0.
- 入队:队不满,先队尾位置传值,再rear=(rear + 1) % maxsize;
- 出队:队不空,先取队头位置元素,front=(front + 1)%maxsize;
- 是否为空:return rear == front;
- 大小:return (rear+maxsize-front)%maxsize;
- 当rear = front时,队列可能为空,或者已经满,所以分两种情况
- { (rear+1)%maxsize == front }==>队列为满
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/630904d78d4802a378f2976f546ccbf8.png)
- { front == rear }==>队列为空
二、队列实现
2.1 队列操作接口
2.1.1 队列操作接口java实现
package com.niss.queue;
public interface Queue<E> {
boolean clear();
boolean isEmpty();
int size();
boolean put(E data);
void remove();
E poll();
E peek();
}
2.2 顺序队列
2.2.1 顺序循环队列java实现
package com.niss.queue;
import java.util.Arrays;
public class SqQueue<E> implements Queue<E> {
private Object[] objects;
int front;
int rear;
private final static int INIT_SIZE = 100;
public SqQueue(int size){
if(size<=0){
throw new RuntimeException("初始化大小异常!");
}
this.objects = new Object[size+1];
this.front = this.rear = 0;
}
public SqQueue(){
this(INIT_SIZE);
}
@Override
public boolean clear(){
try {
Arrays.fill(this.objects, null);
this.front = this.rear = 0;
return true;
}catch (Exception e){
e.printStackTrace();
}
return false;
}
@Override
public boolean isEmpty() {
return front == rear;
}
@Override
public int size() {
return (rear+objects.length-front)%objects.length;
}
public boolean isFull(){
return (rear+1)%objects.length == front;
}
@Override
public boolean put(E data) {
if(isFull()){
throw new RuntimeException("队列已满!");
}
objects[rear] = data;
rear = (rear+1)%objects.length;
return true;
}
@Override
public void remove() {
objects[front] = null;
front = (front+1)%objects.length;
}
@Override
public E poll() {
Object object = peek();
remove();
return (E)object;
}
@Override
public E peek() {
if(isEmpty()){
throw new RuntimeException("空队列!");
}
return (E)objects[front];
}
}
2.3 链式队列
2.3.1 链式队列java实现
package com.niss.queue;
public class LinkedQueue<E> implements Queue<E> {
private static class Node<E>{
E elem;
Node<E> next;
public Node(E elem,Node<E> next){
this.elem = elem;
this.next = next;
}
}
private Node<E> front;
private Node<E> rear;
int length;
public LinkedQueue(){
this.rear = this.front = new Node<E>(null,null);
this.length = 0;
}
private void checkSize(){
if(this.length <= 0){
throw new RuntimeException("空队列!");
}
}
@Override
public boolean clear(){
this.rear = this.front = new Node<E>(null,null);
this.length = 0;
return true;
}
@Override
public boolean isEmpty() {
return this.length == 0;
}
@Override
public int size() {
return this.length;
}
@Override
public boolean put(E data) {
this.rear.next = new Node<E>(data,null);
this.rear = rear.next;
++this.length;
return true;
}
@Override
public void remove() {
checkSize();
this.front = this.front.next;
this.front.elem = null;
--this.length;
}
@Override
public E poll() {
E elem = this.peek();
this.remove();
return elem;
}
@Override
public E peek() {
checkSize();
return this.front.next.elem;
}
}