数据结构-----队列总结

 一.何为队列?

在数据结构中,在有序列表中数据的输入输出分别是由不同端口处理的,输出端称为前端,输入端称为后端,这样会使得先进入的数据先被取出,即它具有先进先出的特性。

二.队列都分为那几类?

我们最常见的队列有:顺序队列,循环队列,链队列以及双向队列;

不过,我们除了必须掌握这几种常见队列也要对不常见的队列进行了解和熟悉,比如说:K队列,优先队列和无锁队列(此文我们主要研究顺序队列,其他队列待更新);

三.深入了解各种队列

1.顺序队列

基本操作的实现:

对于此种队列,在对其进行结构体设计时有三种设计方法,分别如下:

A       

在利用这个结构体时,有个问题。就是maxsize的取值,我们对元素的多少根本无法预计,假如我们宏定义时给maxsize的值小,那么很可能导致在使用的过程中元素的值超过宏定义值。那么有人说,那我定义尽可能大些,不是就不会出现这种情况了吗?当然这种情况是不会出现了,可是会出现另一个问题,对资源的浪费。假如说我们给maxsize宏定义的值为1000000,可是我们实际只用了10个那么剩下的空间岂不是白白浪费了吗?

基于此结构体的这种缺点,我对其进行了改进,得到下面的结构体b


              B        

  此结构体我严格采用多定少用的原则,完美的弥补了a结构体的缺陷,有些人可能就说那这个结构体相当完美了,可是事实真的是那样吗?让我们接着往下看:

在进行队列的基本操作求当前队列的长度时,利用此结构体我们写出得代码如下:

   

有些人可能说没问题啊,就3行代码我们就求出了长度,可是仔细考虑下,这个代码真的没有需要修改的地方了吗?

大家有没有觉得return的语句有点太繁琐。有些人可能说直接用s.tail-s.front就求出结果了,何必搞得那么复杂。可是这样直接求出的结果对吗?

举个例子:假如我们有一个可以存放8个元素的空间,我们给它一个头指针front和尾指针tail,如下图所示:


现在我们有一组数据11,12,13,14,15,要进入这个队列,那么在这个过程中是front指针不动,tail指针向后移动,如下图:



然后我们将这这组数据进行出队列处理:这个过程是front指针向后移动,tail指针不动,如下图:

面如果我们再想进行入队列操作时,如果在5,6,7号位置直接进行的话,势必会导致0---4号位置空间资源的浪费。因此,为了更好的对空间资源进行利用,我们就得想一个办法让我们的尾指针tail回到0号位置,此时的位置关系图如下所示;

此时front指针在5位置,tail指针在0位置,若采用上面的s.tail-s.front计算长度,相减下来为负值,这也是为啥我的代码在计算长度时使用了(s.tail-s.fron+s.maxsize)%s.maxsized,就是为了避免上述情况的发生。

那么,既然上述结构体也并不是完美的,那么我们经过考虑得到可以在结构体中加入一个表示当前元素个数的变量cursize,那么我们得到的新的结构体就如下:

C


在加入当前元素个数的变量后,我们对队列的基本操作的实现就变得比较简单了,具体操作如下;

#include <stdio.h>
#include <assert.h>
#define Queuesize 100
#define true 1
#define false 0
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;

typedef struct{
	int front;
	int tail;
	ElemType *data;
	int maxsize; 
	int cursize;
}queue;
//队列判空 
Status QueueEmpty(queue &s){
	if(s.cursize == 0)
		return OK;
}
//求队列长度 
int QueueLength(queue &s){
	return s.cursize;	
}
//初始化队列 
Status InitQueue(queue &s){
	ElemType *q = (ElemType*)malloc(sizeof(ElemType));
	if(q == NULL);
		return ERROR;
	s.front = s.tail = 0;
	s.cursize == 0;
	return OK;
}
//队列判满 
bool QueueFull(queue &s){
	if(s.cursize == s.maxsize)
		return OK;
}
//清空队列 
Status ClearQueue(queue &s)
{
	s.cursize = 0;
	s.front = s.front = 0;
	return OK;
}
//取队列头元素 
Status GetHead(queue &s,ElemType &x){
	if(QueueEmpty(s))
		return ERROR;
	x=s.data[s.front];
	return OK;	
}
//取队列尾元素 
Status GetTail(queue &s,ElemType &x){
	if(QueueEmpty(s))
		return ERROR;
	x=s.data[s.tail];
	return OK;		
}
//插入元素X为s的新队尾元素 
Status EnQueue(queue &s,ElemType x){
	if(QueueFull(s))
		return ERROR;
	s.data[s.tail] = x;
	s.tail = (s.tail + 1) % s.maxsize;
	return OK;
}
//删除S中队头元素,并用e返回其值 
Status DeQueue(queue &s,ElemType &e)
{
	if (QueueEmpty(s))			/* 队列空的判断 */
		return ERROR;
	e=s.data[s.front];				/* 将队头元素赋值给e */
	s.front=(s.front+1)%s.maxsize;	/* front指针向后移一位置, */								/* 若到最后则转到数组头部 */
	return  OK;
}
int main(){
	printf("hello word");
}
2.链队列

链队列在构造结构体时如下所示:


具体的基本功能实现类似于顺序表的实现。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值