队列
队列是只能在一端进行插入,一端进行删除的线性表。允许插入的一端称为队尾,允许删除的一端为队头。跟我们平常排队买东西是一样的,后来者要插入时只能排在队尾,买完东西的人是从队头出去的(删除)。因为队列中队尾和队头都可以进行操作,所以定义两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置。
既然队列也是线性表,那么也分顺序存储结构和链式存储结构。在队列的顺序存储结构中,在队头进行删除元素的操作,在队尾插入元素,可能导致分配的数组空间浪费很大一部分内存,很不明智,因此出现了循环队列。循环队列是指队列头尾相接的顺序存储结构。当队列为空时,front=rear;当队列满时,数组中还有一个空闲单元。
当rear>front时,也就是队尾指针指向的数组下标大于队头指针指向的数组下标,此时队列的长度为rear-front;当rear<front时,此时队列的长度为rear-front+QueSize;所以队列的长度的通用计算公式为(rear-front+QueSize)%QueSize。
一.顺序存储结构
1.队列的结构定义
代码实现:
class SqQueue{
int maxSize=8;
Object[] array=new Object[maxSize];
int front;
int rear;
}
2.初始化一个空循环队列
代码实现:
public static void initQueue(SqQueue sq){
sq.front=0;
sq.rear=0;
}
3.计算队列的长度
代码实现:
public static int calculateLength(SqQueue sq){
int length=(sq.rear-sq.front+sq.maxSize)%sq.maxSize;
return length;
}
4.循环队列的入队列操作
算法思路:
1. 判断队列是否满,队列已满的判定条件为队列中还有一个空闲单元,%QueSize是考虑到队列的最后一个位置,如果直接rear+1则指针溢出队列,而求余则将指针指向队头第一个位置;
2. 队尾(即rear指针指向的位置)插入元素;
3. rear指针向后移一位,%QueSize原因如1;
代码实现:
public static void EnQueue(SqQueue sq,Object e){
//判断队列是否满
if((sq.rear+1)%sq.maxSize==sq.front){
System.out.println("队列已满");
}else{
//队尾插入元素e
sq.array[sq.rear]=e;
//队尾指针向后移一位
sq.rear=(sq.rear+1)%sq.maxSize;
}
}
5.循环队列的出队列操作
算法思路:
1. 判断队列是否为空,队列为空的判定条件为rear==front;
2. front指针后移一位;
代码实现:
public static void DeQueue(SqQueue sq){
//判断队列是否为空队列
if(sq.rear==sq.front){
System.out.println("队列为空");
}else{
//队头元素赋值给e
Object e=sq.array[sq.front];
//指针后移一位
sq.front=(sq.front+1)%sq.maxSize;
}
}
完整代码:
package com.java.Queue;
import java.util.Arrays;
public class QueueTest {
static SqQueue sq=new SqQueue();
public static void main(String[] args){
EnQueue(sq,"A");
EnQueue(sq,"B");
EnQueue(sq,"C");
EnQueue(sq,"D");
DeQueue(sq);
DeQueue(sq);
System.out.println(sq);
System.out.println(calculateLength(sq));
}
//循环队列的出队列操作
public static void DeQueue(SqQueue sq){
//判断队列是否为空队列
if(sq.rear==sq.front){
System.out.println("队列为空");
}else{
//队头元素赋值给e
Object e=sq.array[sq.front];
sq.array[sq.front]=null;
//指针后移一位
sq.front=(sq.front+1)%sq.maxSize;
}
}
//循环队列的入队列操作
public static void EnQueue(SqQueue sq,Object e){
//判断队列是否满
if((sq.rear+1)%sq.maxSize==sq.front){
System.out.println("队列已满");
}else{
//队尾插入元素e
sq.array[sq.rear]=e;
//队尾指针向后移一位
sq.rear=(sq.rear+1)%sq.maxSize;
}
}
//计算循环队列的长度
public static int calculateLength(SqQueue sq){
int length=(sq.rear-sq.front+sq.maxSize)%sq.maxSize;
return length;
}
//初始化一个空循环队列
public static void initQueue(SqQueue sq){
sq.front=0;
sq.rear=0;
}
}
class SqQueue{
int maxSize=8;
Object[] array=new Object[maxSize];
int front;
int rear;
@Override
public String toString() {
return "SqQueue [maxSize=" + maxSize + ", array=" + Arrays.toString(array) + ", front=" + front + ", rear="
+ rear + "]";
}
}
二.链式存储结构
队列的链式存储结构和单链表差不多,只不过之只能在队尾插入元素在队头删除元素。还有一个区别是链式存储结构中队头指针指向的是队列的头结点,队尾指针指向队尾结点;而在顺序存储结构中,队头指针指向队列的队头元素,而队尾指针指向队尾元素的下一结点。队列的链式存储结构也是不需要事先分配内存空间的。
1.链式队列结点
class QNode{
Object data;
QNode next;
public QNode(Object data,QNode next){
this.data=data;
this.next=next;
}
@Override
public String toString() {
return "QNode [data=" + data + ", next=" + next + "]";
}
}
2.初试化空队列,空队列时front和rear都指向头结点
class LinkQueue{
static QNode front=new QNode("头结点",null);
QNode rear=front;
}
3.入队操作(尾进)
1. 将新结点赋值给队尾指针的下一个元素;
2. 将队尾指针重新指向新结点;
代码实现:
public static void EnLinkQueue(LinkQueue lq,QNode node){
lq.rear.next=node;
lq.rear=node;
}
4.出队操作(头出)
1. 先判断队列栈中是否有元素;
2. 若非空栈,头结点后移一位;
3. 如果头结点之后的结点为要出栈的元素,rear指向front;
代码实现:
public static void DeLinkQueue(LinkQueue lq){
//先判断队列栈中是否有元素
if(lq.front==lq.rear){
System.out.println("空栈");
}else{
//要出栈的元素
QNode p=lq.front.next;
//头结点后移一位
lq.front.next=p.next;
}
//如果头结点之后的结点为要出栈的元素,rear指向front
if(lq.rear==lq.front.next){
lq.rear=lq.front;
}
}
完整代码:
package com.java.Queue;
public class LinkQueueTest {
static QNode node=new QNode("A",null);
static QNode node1=new QNode("B",null);
static LinkQueue lq=new LinkQueue();
public static void main(String[] args){
EnLinkQueue(lq,node);
System.out.println(lq.rear);
EnLinkQueue(lq,node1);
System.out.println(lq.rear);
DeLinkQueue(lq);
System.out.println(lq.front.next);
}
//出队操作(头出)
public static void DeLinkQueue(LinkQueue lq){
//先判断队列栈中是否有元素
if(lq.front==lq.rear){
System.out.println("空栈");
}else{
//要出栈的元素
QNode p=lq.front.next;
//头结点后移一位
lq.front.next=p.next;
}
//如果头结点之后的结点为要出栈的元素,rear指向front
if(lq.rear==lq.front.next){
lq.rear=lq.front;
}
}
//入队操作(尾进)
public static void EnLinkQueue(LinkQueue lq,QNode node){
lq.rear.next=node;
lq.rear=node;
}
}
//初始化空队列,空队列时front和rear都指向头结点
class LinkQueue{
static QNode front=new QNode("头结点",null);
QNode rear=front;
}
class QNode{
Object data;
QNode next;
public QNode(Object data,QNode next){
this.data=data;
this.next=next;
}
@Override
public String toString() {
return "QNode [data=" + data + ", next=" + next + "]";
}
}

浙公网安备 33010602011771号