基本介绍
与栈相对,队列是一种先进先出(First In First Out)的线性表,操作的规则是按照到达的顺序来释放元素,所有的插入在表的一端进行,而所有的删除都在表的另一端进行。
主要元素
队头(front)
队尾(rear)
主要操作
入队列(enQueue)
出队列(deQueue)
取队首元素(getFront)
判断队列是否为空
抽象数据类型
语言仍然采用Java
package top.zhanglugao.queue;
/***
* 队列抽象数据类型
* @param <T>
*/
public interface Queue<T> {
void clear(); //清空队列
boolean enQueue(T t); //入队
T deQueue(); //出队
T getFront(); //获取队首元素
boolean isEmpty(); //判断队列是否为空
boolean isFull(); //判断队列是否已满
}
实现方式
队列跟栈一样也采用顺序和链式两种方式来实现。采用顺序队列时要注意防止队列的假溢出(下面会详细解释),链式队列采用单链表方式存储,队列中每个元素对应链表中的一个结点。
顺序队列
对于顺序队列很简单的一个想法就是内部维护一个数组,再维护两个int型的变量front与rear标识队列的头与尾,元素入队从尾部进入队列后real++,元素出队时从头部弹出后front++。这种情况下队列就会发生假溢出现象,随着real继续增加到队列的maxSize-1,队列就满了不能再添加元素,但元素出队后0-front的位置其实并没有存储元素,这部分空间没法使用了,就发生假溢出现象。解决方案是做成循环数组,继续利用0-front的这部分空间。
package top.zhanglugao.queue;
public class ArrayQueue<T> implements Queue<T> {
private int maxSize;
private int front;
private int rear;
private T[] st;
/***
* 构造函数,顺序队列初始化时需要指定大小 让存储元素的数组多预留一个空位
*/
public ArrayQueue(int size){
maxSize=size+1;
front=1;
rear=0;
st= (T[]) new Object[maxSize];
}
/***
* 清空队列,跟重新初始化一样
*/
public void clear() {
front=1;
rear=0;
}
/***
* 数据入队
* @param t
* @return
*/
public boolean enQueue(T t) {
//先判断队列是否已满
if(isFull()){
System.out.println("队列已满");
return false;
}
rear=(rear+1)%maxSize;//寻找下一个空位,环形结构 所以需要%maxSize
st[rear]=t;
return true;
}
/***
* 数据出队,如果front=rear,队列中无元素
* @return
*/
public T deQueue() {
if(isEmpty()){
System.out.println("空队列");
return null;
}
T t=getFront();
front=(front+1)%maxSize;//环形增加
return t;
}
public T getFront() {
if(isEmpty()){
System.out.println("空队列");
return null;
}
T t=st[front];
return t;
}
public boolean isEmpty() {
if((maxSize+(rear-front+1))%maxSize==0) return true;
return false;
}
public boolean isFull() {
//还剩一个空位时就要报满
if((rear+2)%maxSize==front)return true;
return false;
}
public static void main(String[] args) {
ArrayQueue<Integer> queue=new ArrayQueue<Integer>(3);
queue.enQueue(1);
queue.enQueue(2);
queue.enQueue(3);
System.out.println("报满---");
queue.enQueue(4);//这句会报队列已满
System.out.println("结束---");
Integer integer = queue.deQueue();//弹出了一个
System.out.println("取队列数据应该为1:"+integer);
Integer front = queue.getFront();
System.out.println("弹出一个后再调用getFront结果应该为2:"+front);
System.out.println("继续添加不应该报满---");
queue.enQueue(4);//这句不会报队列已满
System.out.println("继续添加不应该报满检测结束---");
System.out.print("应该输出队列满");
System.out.println(queue.isFull());
System.out.println("接下来依次将数据移除");
System.out.println(queue.deQueue());
System.out.println(queue.deQueue());
System.out.println(queue.deQueue());
System.out.println(queue.isEmpty());
queue.enQueue(1);
queue.enQueue(1);
queue.enQueue(1);
queue.enQueue(1);
}
}
输出结果如下:
报满---
队列已满
结束---
取队列数据应该为1:1
弹出一个后再调用getFront结果应该为2:2
继续添加不应该报满---
继续添加不应该报满检测结束---
应该输出队列满true
接下来依次将数据移除
2
3
4
true
链式队列
链式队列采用单链表的结构,链接指针的方向是从队列的前端向尾端相连。
类定义
链式比较好理解,直接上代码。
package top.zhanglugao.queue;
import top.zhanglugao.stack.Link;
public class LinkedQueue<T> implements Queue<T> {
private int size;
private Link<T> front;
private Link<T> rear;
public void clear() {
}
/***
* 将t插入队尾
* @param t
* @return
*/
public boolean enQueue(T t) {
if(rear==null){
front=rear=new Link<T>(t,null);
}
else{
rear.setNext(new Link<T>(t,null));
rear=rear.getNext();
}
size++;
return true;
}
public T deQueue() {
if(size==0){
System.out.println("队列为空");
return null;
}
T t=front.getData();
front=front.getNext();
if(front==null){
rear=null;
}
size--;
return t;
}
public T getFront() {
if(size==0){
System.out.println("队列为空");
return null;
}
T t=front.getData();
return t;
}
public boolean isEmpty() {
return size==0;
}
public boolean isFull() {
return true;
}
public static void main(String[] args) {
LinkedQueue<Integer> queue=new LinkedQueue<Integer>();
queue.enQueue(1);
queue.enQueue(2);
queue.enQueue(3);
queue.enQueue(4);
System.out.println(queue.deQueue());
System.out.println(queue.deQueue());
System.out.println(queue.deQueue());
System.out.println(queue.deQueue());
System.out.println(queue.isEmpty());
}
}
顺序队列与链式队列的比较
顺序队列需要指定存储空间,链式队列可以更好的满足大小无法估计的情况,都不允许访问队列内容元素。时间复杂度都为O(1)
队列的应用
只要满足先来先服务特性的应用均可采用队列,例如:
消息缓冲器
邮件缓冲器
操作系统的资源管理
宽度优先搜索
计算机硬设备之间的通信也需要队列作为数据缓冲