队列的定义
队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出(First In First Out)的线性表,简称FIFO。允许插入的一端称为队尾,允许删除的一端叫做队头。
队列的抽象数据类型
C语言中的定义
InitQuene(*Q):初始化操作,建立一个空队列Q
DestroyQueue(*Q):若队列Q存在,则销毁它。
ClearQueue(*Q):将队列Q清空
QueueEmpty(Q):若队列Q为空,返回True,否则false
GetHead(Q,*e):若队列Q存在且非空,用e返回队列的队头元素
EnQueue(*Q,e):若队列Q存在,插入新元素e到队列Q中并成为队尾元素
DeQueue(*Q,*e):删除队列Q中对头元素,并用e返回其值。
QueueLength(Q):返回队列Q的元素个数
但是顺序存储,若不是循环队列,算法的时间性能是不高的,但循环队列有面临着数组可能会溢出的问题,所以我们还要研究一下不需要担心队列长度的链式存储结构。
顺序队列
顺序队列存储结构称为顺序队列,顺序队列实际上是运算受限的顺序表
顺序队列的表示
和顺序表一样,顺序队列利用内存中一段连续的存储空间来存放当前队列中的元素。由于队列的队头和队尾是变化的,设置两个指针front和real分别指示队头和队尾元素,它们的初值在队列初始化时应置为0
顺序队列的基本操作
入队时:将新元素插入rear所指的位置的后一位
出队时:删去front所指的元素,然后将front加1并返回被删元素
顺序表的溢出现象
- 下溢
: 当队列为空时,做出队运算产生的溢出现象。下溢
是正常现象,常用作程序控制转移的条件。
- 真上溢
:当队列满时,做进栈运算产生空间溢出的现象。真上溢
是一种出错状态,应设法避免。
- 假上溢
:由于入队和出对操作中,头尾指针只增加不减小,致使被删元素的空间永远无法被重新利用。当队列中的实际元素的个数远远小于内存中分配的空间时,也可能由于尾指针已超越向量空间的上界而不能做入队操作。
循环队列
如下图所示,这种头尾相连的顺序存储结构称为循环队列(circular queue)
循环队列中需要注意的几个重要问题
- 队空的判定条件,队空的判定条件是front=rear
- 堆满的判定条件是(rear+1)%QueueSize=front
"使用Java 来模拟循环队列的实现原理"
package org.moxiu.StackandQueue;
/**
* Created by gyg on 2017/2/10.
* 模拟循环队列的实现
*/
public class CircularQueue<E> {
//对象数组,队列最多存储a.length-1个对象
private Object[] element;
//默认初始化大小
private static final int DEFAULT_SIZE=10;
//队首下标
int front;
//队尾下标
int rear;
// 定义无参构造函数,默认长度为10
public CircularQueue(){
this(DEFAULT_SIZE);
}
//定义有参构造函数
public CircularQueue(int len){
element = new Object[len];
front = 0;
rear=0;
}
/**
*将一个对象追加到队列尾部
*@param obj
* return 队列满时返回false,否则返回true
*/
public boolean push(E obj){
if((rear+1)%element.length==front){
return false;
}else{
element[rear]=obj;
rear=(rear+1)%element.length;
return true;
}
}
/**
*将一个队列的头部元素出队。
* @return
* @author gyg
*/
public Object pop(){
if(rear == front){
return null;
}else{
Object obj = element[front];
element[front] = null;
front=(front+1)%element.length;
return obj;
}
}
/**
* 获取队列长度
* @param
*/
public int size(){
if(rear>front)
{
return rear-front;
}
return front-rear;
}
/**
* 判断队列是否为空
* @param
*/
public boolean isEmpty(){
return rear==front;
}
public static void main(String[] args){
CircularQueue queue = new CircularQueue(5);
queue.push("3");
queue.push("5");
System.out.println(queue.size()); //打印队列的长度
System.out.print(queue.isEmpty()); //判断队列是否为空
queue.pop(); //队列的头元素出队
int size = queue.size(); //使用变量定义队列的长度
for(int i=0;i<size;i++)
{
System.out.print(queue.pop()); //输出队列中所有的元素。
}
}
队列的链式存储结构及实现
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出而已,我们把它简称为链队列。
链队列的存储形式
/**
* Created by gyg on 2017/2/10.
* 被类用于模拟链队列用java的实现
*/
public class LinkQueue<T> {
//链的数据结构
private class Node{
public T data;
public Node next;
//无参构造函数
public Node(){}
//有参构造函数
public Node(T data,Node next){
this.data=data;
this.next=next;
}
}
//队列头指针
private Node front;
//队列尾指针
private Node rear;
//队列长度
private int size=0;
public LinkQueue(){
Node n = new Node(null,null);
n.next=null;
front=rear=n;
}
/**
* 队列入队算法
*/
public void push(T data){
//创建一个节点
Node s = new Node(data,null);
//将尾指针指向新加入的节点,将s节点插入队尾
rear.next=s;
rear=s;
size++;
}
/**
* 队列出队算法
*/
public Object pop(){
if(rear==front){
try{
throw new Exception("堆栈为空");
}catch(Exception e){
e.printStackTrace();
}
return null;
}else{
//定义变量存储队头元素值
Node p = front.next;
T x = p.data;
//将队头元素所在的节点摘链
front.next=p.next;
//判断出队列长度是否为1
if(p.next==null)
rear=front;
//删除节点
p=null;
size--;
return x;
}
}
/**
* 求出队列长度
*/
public int size(){
return size;
}
/**
* 判断队列是否为空
*/
public boolean isEmpty(){
return size==0;
}
/**
* 重写toString方法
*/
public String toString(){
if(isEmpty()){
return "[]";
}else{
StringBuilder sb = new StringBuilder("[");
for(Node current=front.next;current!=null;current=current.next){
sb.append(current.data.toString()+",");
}
int len = sb.length();
return sb.delete(len - 2,len).append("]").toString();
}
}
//测试
public static void main(String[] args){
LinkQueue<Integer> queue=new LinkQueue<Integer>();
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
queue.push(5);
queue.push(6);
System.out.println(queue);
System.out.println("出队:"+queue.pop());
System.out.println("队列长度="+queue.size());
System.out.println(queue);
System.out.println("出队:"+queue.pop());
System.out.println("队列长度="+queue.size());
System.out.println(queue);
System.out.println("出队:"+queue.pop());
System.out.println("队列长度="+queue.size());
System.out.println(queue);
}
}