1、队列的结构特点和操作
复习一下队列:数据结构“队列”与我们日常生活中的排队非常相似,按照先到先办的原则办事,并且严格规定不能加塞,也不允许中途离队。
队列:限定只能在队尾进行插入元素,在表头进行删除。允许插入的一端叫队尾,允许删除的一端叫队头。
1.1循环队列
和顺序栈相类似,再利用顺序分配存储结构实现队列时,除了用一纬数组描述队列中的数据元素的存储区域,还需要设立两个指针front 和 rear 分别表示队头和队尾的位置。
初始化队列时front = rear =0;每当插入一个元素后,rear+1;每当删除一个元素是front++;因此在非空队列时,头指针始终指向队头元素,尾指针始终指向队尾元素的下一个位置。如图是一个最大空间为6 的队列。初始化时如下图
图a表示初始化为一个最大空间为6的空队列。
图b,开始插入元素,尾指针后移。始终指向队尾元素的下一个位置。
图c删除队列元素,头指针加1;
图d继续插入元素,这里如果尾指针在增加一的话指针数组元素就要越界了。
那么还有什么办法呢,如果这样的话,随着删除元素,这个数组空间就会浪费了。
我们可以让尾指针循环呀,这就解决了这个问题。看图:
如图e,这就完美解决了看见浪费的问题
如图f 队列满的时候尾指针和头指针相等
如图g 队列为空的时候尾指针和头指针相等
这样我们就不能部分变队列是空还是满。要解决这个问题的办法有很多,我们可以采取牺牲一个空间,如图h表示队列满。
要想使rear循环,使用公式rear = (rear+1)%(队列最大容量)
下面是整体代码
#include<stdlib,h>
#include<stdio.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFFLOW -2
#define INIT_SIZE 10//初始化队列大小
typedef int QElemtype;
typedef int Status;
typedef struct SqQueue{
QElemtype *base;
int top;
int rear;
}SqQueue;//定义一个线性表
/初始化
Status InitQueue(SqQueue *Q)
{
Q->base=(QElemtype *)malloc(sizeof(QElemtype)*INIT_SIZE);
if(Q->base)
{
Q->top=0;
Q->rear=0;
return OK;
}
return ERROR;
}
//队列的长度
int QueueLength(SqQueue Q)
{
return ((Q.rear-Q.top+INIT_SIZE)%INIT_SIZE) ;
}
//入队
Status EnQueue(SqQueue *Q,QElemtype e)
{
if((Q->rear+1)%INIT_SIZE+1 == Q->top) return ERROR;
Q->base[Q->rear]= e;
Q->rear = (Q->rear+1)%INIT_SIZE;
return OK;
}
//出队
Status DeQueue(SqQueue *Q,QElemtype *e)
{
if(Q->top == Q->rear)return ERROR;
*e = Q->base[Q->top];
Q->top = (Q->top+1)%INIT_SIZE;
return OK;
}
//访问
void visit(QElemtype e)
{
printf("%d",e);
}
void Tr(SqQueue Q,void (*visit)(QElemtype e))
{
while(Q.top != Q.rear)
{
(*visit)(Q.base[Q.top]);
Q.top=(Q.top+1)%INIT_SIZE;
}
}
int main()
{
SqQueue Q;
if(InitQueue(&Q))
printf("初始化成功\n");
for(int i=0;i<9;i++)
{
EnQueue(&Q,i);
}
Tr(Q,visit);
int a = QueueLength(Q);
printf("%d",a);
return 0;
}