赞
踩
队列(queue),是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
允许插入的一端称为队尾,允许删除的一端称为队头。
假设队列是
q
=
(
a
1
,
a
2
,
.
.
.
.
.
.
,
a
n
)
q=(a_1,a_2,......,a_n)
q=(a1,a2,......,an),那么
a
1
a_1
a1就是队头元素,而
a
n
a_n
an就是队尾元素。
同样是线性表,队列也有类似线性表的各种操作,不同的就是插入数据只能在队尾进行,删除数据只能在队头进行。
线性表有顺序存储和链式存储。
栈是线性表,所以有这两种存储方式。
同样,队列作为一种特殊的线性表,也同样存在这两种存储方式。
假设一个队列有n个元素,则顺序存储的队列需建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元,数组下标为0的一端即是队头。
所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度为o(1).
与栈不同的是,队列元素的出列是在队头,即下标为0的位置,那也就意味着,队列中的所有元素都得向前移动,以保证队列的队头,也就是下标为0的位置不为空,此时的时间复杂度为o(n).
但是,我们不一定让队头一定要在下标为0的位置!
front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front等于rear时,此队列不是还剩一个元素,而是空队列。
假设一长度为 5 的数组,初试状态,空队列如下图左,front 与 rear 指针均指向下标为 0 的位置。
然后入队 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4 a1,a2,a3,a4.
front 指针仍然指向下标为 0 的位置,rear 指针指向下标为 4 的位置。
出队
a
1
,
a
2
a_1,a_2
a1,a2.
front 指针仍然指向下标为 2 的位置,rear 不变。
再入队 a 5 a_5 a5,此时 front 指针不变,rear 指针移动到数组之外。
嗯?数组之外,那将是哪里?
假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1 的地方还是空闲的,我们把这种现象叫做“假溢出”。
刚才地例子继续,rear 可以改为指向下标为 0 的位置,这样就不会造成指针指向不明的问题了。
我们把队列的这种头尾相接的顺序存储结构称为循环队列。
接着入队
a
6
a_6
a6,将它放在下标为 0 的地方,rear 指针指向下标为 1 处。
若再入队
a
7
a_7
a7, 则rear 指针就与 front 指针重合,同时指向下标为 2 的位置。
之前说,空队列时,front 等于 rear ,现在当队列满时,也是front 等于 rear ,那么究竟该如何判断此时的队列究竟是空还是满呢?
设置一个标志变量 flag ,当 front==rear ,且 flag=0 时,队列为空;
当 front==rear ,且 flag=1 时,队列为满;
当队列空时,条件就是 front==rear 队列当队列满时,我们修改其条件,保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。我们就认为此队列已经满了。
/* 循环队列的顺序存储结构 */
typedef struct
{
QElemType data[MAXSIZE];
int front; /* 头指针 */
int rear; /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
}SqQueue;
/* 初始化一个空队列Q */
Status InitQueue(SqQueue *Q)
{
Q->front=0;
Q->rear=0;
return OK;
}
/* 返回Q的元素个数,也就是队列的当前长度 */
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
/* 若队列未满,则插入元素e为Q新的队尾元素 */
Status EnQueue(SqQueue *Q,QElemType e)
{
if ((Q->rear+1)%MAXSIZE == Q->front) /* 队列满的判断 */
return ERROR;
Q->data[Q->rear]=e; /* 将元素e赋值给队尾 */
Q->rear=(Q->rear+1)%MAXSIZE;/* rear指针向后移一位置, */
/* 若到最后则转到数组头部 */
return OK;
}
/* 若队列不空,则删除Q中队头元素,用e返回其值 */
Status DeQueue(SqQueue *Q,QElemType *e)
{
if (Q->front == Q->rear) /* 队列空的判断 */
return ERROR;
*e=Q->data[Q->front]; /* 将队头元素赋值给e */
Q->front=(Q->front+1)%MAXSIZE; /* front指针向后移一位置, */
/* 若到最后则转到数组头部 */
return OK;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。