1.定义:队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表。
允许插入的一端-----队尾(rear),允许删除的一端----队头(front)。
2.特点:先进先出(FIFO)
3.链队列
用链表表示的队列
//LsQueue.h
#include "iostream"
typedef int ElemType;
struct quenode //链队列结点的结构描述
{
ElemType data;
quenode *next;
};
class LsQueue
{
private:
quenode *front,*rear;
public:
LsQueue();
~LsQueue();
int IsEmpty();
void Display();
void AddQ(ElemType x);
ElemType DelQ();
ElemType GetFront();
};
空的链队列的判决条件:Q.front==Q.rear,头指针、尾指针均指向头结点。
入队操作
链队列的基本操作
//初始化一个空的链队列
int InitQueue( LinkQueue * Q ) {
Q->front=Q->rear=( )malloc(sizeof( ) );
if(! Q->front) return FALSE;
Q->front->next=NULL;
return TRUE;
}
//销毁队列
int DestroyQue(LinkQueue * Q) {
while(Q->front) {
Q->rear=(Q->front)->next;
free(Q->front);
Q->front=Q->rear;
}
return TRUE;
}
//插入元素e为新的队尾元素
int EnterQueue(LinkQueue *Q,QElemType e) {
p=( )malloc(sizeof(LinkQueueNode));
if(! p) return FALSE;
p->data=e; p->next=NULL;
Q->rear->next=p;
Q->rear=p;
return TRUE;
}
//删除队列的队头元素,以e返回
int DeleteQueue(LinkQueue *Q,ElemType *e) {
if(Q->front==Q->rear) return FALSE;
p=Q->front->next; *e=p->data;
Q->front->next=p->next;
if(Q->rear==p) Q->rear=Q->front ;
free(p);
return TRUE;
}
//LsQueue.cpp
#include "LsQueue.h"
#include "iostream"
using namespace std;
LsQueue::LsQueue() //构造函数,初始化一个空队列
{
quenode *p;
p=new quenode;
p->next=NULL;
front=rear=p;
}
int LsQueue::IsEmpty() //判断队列是否为空
{
if (front==rear)
return 1;
else
return 0;
}
ElemType LsQueue::GetFront() //取队首元素,不出队
{
ElemType x;quenode *p;
if (front==rear)
{
cout<<"\n Queu Is Empty!"<<endl;
x=-1;
}
else
{
p=front->next;
x=p->data;
}
return x;
}
void LsQueue::AddQ(ElemType x) //值为x的结点入队
{
quenode *s;
s=new quenode;
s->data=x;
s->next=NULL;
rear->next=s;
rear=s;
}
ElemType LsQueue::DelQ() //出队一个元素
{
ElemType x;quenode *p;
if (front==rear)
{
cout<<"\n 队列为空。"<<endl;
x=-1;
}
else{
p=front->next; //p指向第一个数据结点
front->next=p->next;
if (p->next==NULL) rear=front; //防止尾指针丢失
x=p->data;
delete p;
}
return x;
}
4.循环队列
引出:设顺序队列的预定义长度为M,则:
当front=0,rear=M时,再有元素入队发生溢出----真溢出
当front≠0,rear=M时,再有元素入队发生溢出----假溢出
解决方案:
有如下两种方法:
1)采用平移元素的方法。一旦发生“假溢出”,就把整个队列的元素平移到存储区的首部。显然平移元素的方法效率是很低的。
2)将整个队列作为循环队列来处理:把队列想成环形,让sq[0]接在sq[M-1]之后,若++rear==M,则令rear=0;
利用“模”运算
入队:rear=(rear+1)%M
出队:front=(front+1)%M
然而会出现新的问题,队空:front == rear
队满:front == rear,如下图所示:
故提出以下解决问题的方案:
(1)另外设一个标志flag以区别队空与队满条件:
当front==rear且flag=0时为队空,当front==rear且flag=1时为队满。
(2)设记录实际队列元素个数的数据成员来区别
(3)牺牲一个队列元素空间以区别队空与队满条件
队空:front==rear
队满:(rear+1)%M==front
即拥有MAXSIZE个数组元素的数组仅能表示一个长度为MAXSIZE-1的循环队列。
程序实现
//SeQueue.h
//************顺序栈类定义*************
typedef int ElemType; //数据元素的类型
const int MAXSIZE=100; //数组的容量
class SeQueue
#include "SeQueue.h"
#include "iostream"
using namespace std;
int SeQueue::Empty() //判断循环队列是否为空
{
if (rear==front)
return 1;
else
return 0;
}
void SeQueue::Display() //输出队列
{
int k;
if (front==rear)
cout<<"\n Queue is Empty!"<<endl;
else
{for(k=front;k <= rear;k=(k+1)%MAXSIZE) cout<<elem[k];
}
}
ElemType SeQueue::GetFront() //取队列队首元素,不出队
{
ElemType x;
if (front==rear){
cout<<"\n Queu is Empty!"<<endl;
x=-1;
}
else
x=elem[(front+1)%MAXSIZE];
return x;
}
void SeQueue::AddQ(ElemType x) //进队操作
{
if ((rear+1)%MAXSIZE==front)
cout<<"\n Queu is Full!"<<endl;
else
{
rear=(rear+1)%MAXSIZE;
elem[rear]=x;
}
}
ElemType SeQueue::DelQ()
{
if (front==rear)
{
cout<<"\n Queue is Empty!"<<endl; //表明队空,未曾出队
return -1;
}
else{
front=(front+1)%MAXSIZE; //出队操作
return elem[front];
}
//SeQueue.cpp
#include "iostream"
#include "SeQueue.h"
using namespace std;
int SeQueue::Empty() //判断循环队列是否为空
{
if (rear==front)
return 1;
else
return 0;
}
void SeQueue::Display() //输出队列
{
int k;
if (front==rear)
cout<<"\n Queue is Empty!"<<endl;
else
{for(k=front;k <= rear;k=(k+1)%MAXSIZE) cout<<elem[k];
}
}
ElemType SeQueue::GetFront() //取队列队首元素,不出队
{
ElemType x;
if (front==rear){
cout<<"\n Queu is Empty!"<<endl;
x=-1;
}
else
x=elem[(front+1)%MAXSIZE];
return x;
}
void SeQueue::AddQ(ElemType x) //进队操作
{
if ((rear+1)%MAXSIZE==front)
cout<<"\n Queu is Full!"<<endl;
else
{
rear=(rear+1)%MAXSIZE;
elem[rear]=x;
}
}
ElemType SeQueue::DelQ()
{
if (front==rear)
{
cout<<"\n Queue is Empty!"<<endl; //表明队空,未曾出队
return -1;
}
else{
front=(front+1)%MAXSIZE; //出队操作
return elem[front];
}
}
队列的应用-----报数问题
报数问题:设有n个人站成一排,从左到右的编号分别为1~n,从左到右报数”1,2,3,1,2,3“数到”1“和”2“的人出列,数到”3“的人立即站在队伍的最右端。报数过程反复进行,直到n个人都出列为止。
算法思想:先将n个人的编号进队,然后反复执行如下操作:
(1)出队一个元素,输出其编号;
(2)再出队一个元素,输出其编号;
(3)若队列不空,则出队一个元素,然后将该元素再进队。
直到队列为空。