队列1---顺序队列---循环队列

队列

队列(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指针指向队尾元素的下一个位置,这样当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 不变。

问题1

再入队 a 5 a_5 a5,此时 front 指针不变,rear 指针移动到数组之外。

嗯?数组之外,那将是哪里?

问题2

假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经占用,再向后加,就会产生数组越界的错误,可实际上,我们的队列在下标为0和1 的地方还是空闲的,我们把这种现象叫做“假溢出”。

自然地引出-----循环队列

刚才地例子继续,rear 可以改为指向下标为 0 的位置,这样就不会造成指针指向不明的问题了。

我们把队列的这种头尾相接的顺序存储结构称为循环队列。
在这里插入图片描述
接着入队 a 6 a_6 a6,将它放在下标为 0 的地方,rear 指针指向下标为 1 处。

若再入队 a 7 a_7 a7, 则rear 指针就与 front 指针重合,同时指向下标为 2 的位置。
在这里插入图片描述

问题3

之前说,空队列时,front 等于 rear ,现在当队列满时,也是front 等于 rear ,那么究竟该如何判断此时的队列究竟是空还是满呢?

法1:

设置一个标志变量 flag ,当 front==rear ,且 flag=0 时,队列为空;

当 front==rear ,且 flag=1 时,队列为满;

法2

当队列空时,条件就是 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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值