普通顺序队列的不足以及解决方法

我们假设一个队列有n个元素,则顺序存储的队列需建立一个大于n的数组,并把队列的所有元素存储在数组的前n个单元,数组下标为0的一端即是队头。所谓的入队列操作,其实就是在队尾追加一个元素,不需要移动任何元素,因此时间复杂度为0(1)。

可有时想想,为什么出队列时一定要全部移动呢,如果不去限制队列的元素必须存储在数组的前n个单元这一条件,出队的性能就会大大增加。也就是说,队头不需要一定在下标为0的位置,比如也可以是a[1]等。(由于要保证对头在数组下标为0处,不得不把后面的数组元素向前移动,因此出队的时间复杂度为O(n))

为了避免当只有一个元素时,队头和队尾重合使处理变得麻烦,所以引入两个指针,front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样当front等于rear时,此队列不是还剩一个元素,而是空队列。

假设是长度为5的数组,初始状态,空队列如所示,front与 rear指针均指向下标为0的位置。然后入队a1、a2、a3、a4, front指针依然指向下标为0位置,而rear指针指向下标为4的位置。
在这里插入图片描述
在这里插入图片描述
出队a1、a2,则front指针指向下标为2的位置,rear不变,如下图所示,再入队a5,此时front指针不变,rear指针移动到数组之外。嗯?数组之外,那将是哪里?

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

总结:
入队时:将新元素插入rear所指的位置,然后将rear加1。
出队时:删去front所指的元素,然后将front加1并返回被删元素。
注意:
(1)当头尾指针相等时,队列为空。
(2)在非空队列里,队头指针始终指向队头元素,队尾指针始终指向队尾元素的下一位置。
(3)长度:rear-front
存在问题编辑
在普通顺序队列中,入队操作就是先将尾指针rear后移一个单元(rear++),
然后将元素值赋给rear单元(data[rear]=X)。
出队时.则是头指针front后移(front++)。
像这样进行了一定数量入队和出队操作后,
可能会出现这样的情况:尾指针rear已指到数组的最后一个元素.
即rear==MAXLEN-1.此时若再执行入队操作,
便会出现队满“溢出”。然而,由于在此之前可能也执行了若干次出队操作.
因而数组的前面部分可能还有很多闲置的元素空间,即这种溢出并非是真的没有可用的存储空间,
故称这种溢出现象为“假溢出”。
显然,必须要解决这一似溢出的问题,否则顺序队列就没有太多使用价值。

解决方法:引入循环队列

//普通顺序队列结构

#ifndef   _queue_h
#define   _queue_h

#include<iostream>
#include<stdlib.h>

#define maxsize 10

typedef struct queue 
{	
	int data[maxsize];
	int rear;
	int front;
}queue;

extern void initqueue(queue* s);
extern int enqueue(queue* s, int value);
extern int dequeue(queue* s, int value);
extern int queuelength(queue* s);
extern void printqueue(queue* s);

#endif // ! _queue_h

//以下是操作方法,也会带来种种不便。

#include"queue.h"
void initqueue(queue* s)
{
	s->front = s->rear = 0;

	return;

}
int enqueue(queue* s,int value)//进队
{
	if (s->rear >= maxsize)//只能这样判断队满
	{
		return 0;
	}

	s->data[s->rear] = value;

	s->rear++;

	return 1;

}
int dequeue(queue* s, int value)//出队
{
	if (s->front == s->rear)
	{
		return 0;
	}

	value = s->data[s->front];

	s->front++;

	return 1;
}
/*
int dequeue(queue* s, int value)//出队
{
	int i = 0;

	if (s->front == s->rear)
	{
		return 0;
	}

	value = s->data[s->front];

	for (i = s->front; i < s->rear-1; i++)
	{
		s->data[i] = s->data[i + 1]; //出队后,剩下的所有元素向前移动,那么队尾指针就要减一,且当只有一个元素时,rear==front
	}                                 这样处理较为复杂(初始化时rear和front也相等),

	s->rear--;//出队按理来说是处理对头的,因为所有元素向前移动,这里不得不改变队尾指针

	return 1;
}
*/
//以上出队函数较复杂/,一般不采用
int queuelength(queue* s)
{

	return s->rear - s->front;//队列长度

}
void printqueue(queue* s)
{
	int i = 0;

	for (i = s->front; i < s->rear; i++)
	{
		printf("%d\t", s->data[i]);
	}

	printf("\n");

	return;
}
#include"queue.h"
int main(void)
{

	int i = 0, k = 0;

	queue* s = NULL;

	s = (queue*)malloc(sizeof(queue));

	initqueue(s);

	for (i = 1; i <=5; i++)
	{
		enqueue(s,i);
	}

	dequeue(s,k);

	printqueue(s);

	system("pause");

	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值