在上一篇文章中我介绍了一些与栈有关的内容,在这篇文章中我主要介绍队列,队列和栈一样都是一种操作受限的线性表。为什么说队列操作受限,因为普通线性表在任意位置都能够进行插入和删除的操作,然而,队列却不是,队列是只能在一端进行插入另一端进行删除的线性表,这也就是为什么说队列操作受限。
我就不废话了,接下来我就来介绍一下有关队列的内容,理解队列是什么能更容易帮助你们理解有关队列的操作,能让你们达到事半功倍的效果,队列与栈一样也分为两种类型一种是顺序队列另一种是链队列,这篇文章主要介绍顺序队列。
队列是一种先进先出的线性表,也就是说在队列的一端进行插入元素另一端进行删除元素,在队列中允许插入的一端称为队尾,允许删除的一端称为队头。
顺序队列的实现是通过循环队列实现的,循环队列就是将顺序队列变成一个环状的空间。
为什么会让循环队列来表示顺序队列呢,因为顺序队列会造成假溢出。
假溢出:队列实际的空间并未占满,但却无法在插入新元素。
如何解决假溢出呢,解决这个问题是通过循环队列解决的。
循环队列的实现
头、尾指针以及队列元素之间的关系不变,只是在循环队列中,头、尾指针依环状增加1的操作可以通过模运算来实现。通过取模,头指针和尾指针就可以在顺序表空间内以头尾衔接的方式循环移动。
注意:在循环队列中存储的元素个数往往比顺序队列最大存储个数少一,因为rear指向队尾的后一个元素。
介绍完循环队列的含义之后,就该进行代码操作了
队列的顺序存储结构
typedef struct queue{
elemtype* base;
int rear;
int front;
}SqQueue;
1、队列初始化
Status initqueue(SqQueue &Q){
Q.base=new int[MAXSIZE]; //分配一个大小为MAXSIZE空间并把地址赋值给Q.base;
if(!Q.base) //如果分配失败,直接结束
return ERROR;
Q.rear=Q.front=0; //让front与rear都等于0,使队列为空
return OK;
}
2、队列的入队
Status pushqueue(SqQueue &Q,int e){
if((Q.rear+1)%MAXSIZE==Q.front) //判断队列是否满了
return ERROR;
Q.base[Q.rear]=e; //如果队列未满。将e的放在末尾
Q.rear=(Q.rear+1)%MAXSIZE; //rear后移一位
return OK;
}
3、队列的出队
Status popqueue(SqQueue &Q,int e){
if(Q.rear==Q.front) //判断队列是否为空
return ERROR;
e=Q.base[Q.front]; //把队头元素赋值给e
Q.front=(Q.front+1)%MAXSIZE; //front后移一位
return OK;
}
4、队列的长度
int queueLength(SqQueue &Q){
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE; //返回队列的长度
}
5、队列的队头元素
Status getelem(SqQueue &Q,int e){
if(Q.rear==Q.front) //队列是否为空
return ERROR;
e=Q.base[Q.front]; //如果队列不为空,将对头元素赋值给e
return OK;
}
以上就是有关队列的介绍了,内容到此也就结束了,希望大家对队列有进一步的了解。