栈和队列 --循环队列
前言
前情提要:之前的文章讲了队列和栈的基本概念 ,今天来讲队列的具体实现
一、队列是什么?
队列的定义
队列定义:队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是先进先出(first in first out)的数据结构。
既可以头部插入尾部删除,也可以头部删除尾部删除。
队列最好的实现方式为循环链表。
原因:指针指向尾节点则尾节点的next 则为头节点。
典型例子为操作系统中的作业排队。
入队的称为队尾(rear),出队的称为队头(front)。当其中无元素时为空队。
1.2时间复杂度比较
队列
队尾插入 时间复杂度为0(n)
出的时候不挪动数据0(1)
与栈作比较
顺序栈 :入栈时间复杂度0(1)
出栈时间复杂度0(1)
链栈 :入栈时间复杂度0(1)
出栈时间复杂度0(1)
1.3 难题及解决
1.入队和出队的时间复杂度降低为0(1)?
措施 :循环队列
引发问题 :空 front 0 rear 0 --满 front 0 rear 0
图示方案一 :判断 (rear+1)%size(有效个数)==0;即 用(4+1)%5= =0来判断;
方案二: 多申请一个变量来记录有效节点的个数。能简化代码,便于理解。但实际应用要再行考虑。
————————————————
二、队列的实现
2.1 循环队列结构体实现
代码如下(示例):
#define MAXSIAZE 100
typedef struct Queue
{
ELEM_TYPE *base;
int front;//队列不空,队头元素
int rear;//队列不空,队尾的下一个位置
// int length;// 保存有效长度(可选)
}Queue,PQueue;
2.2 循环队列基本操作
初始化
入队
出队
获取顶部元素
获取有效元素个数
判空
判满
清空
销毁
(没有有效值个数则不存在扩容操作)
代码如下(示例):
void Init_Queue(PQueue pq)
{
pq->base=(ELEM_TYPE *)malloc(sizeof(ELEM_TYPE)*MAXQSIZE);
assert(pq->base!=NULL);
pq->front=0;
pq->rear =0;
}
bool push(PQueue pq ,ELEM_TYPE val);
{ //assert
if(isfull(pq)) return false;
pq->base[pq->rear]=val;
if((rear+1)%MAXQSIZE==0){
printf("NO ROOM");
return false;
}//没空间了,要覆盖的话可以考虑修改代码
pq->rear = (pq->rear + 1) % MAXQSIZE;
return true; // 成功添加元素
}
bool pop(PQueue pq ,ELEM_TYPE *r)
{
//assert pq
if(isempty(pq))
{return false;}
*r=pq->base[pq->front];
pq->front=(pq->front+1)%MAXSIAZE;
return true;
}
bool top(PQueue pq ,ELEM_TYPE *r){
//assert pq
if(isempty(pq))
{return false;}
*r=pq->base[pq->front];
//pq->front=(pq->front+1)%MAXSIAZE;
//与pop区别 :不用改指针
return true;
}
//********重难点理解****************//
int Get_length(PQueue pq)
{ //assert pq
//判断rear 和 front的大小有点繁琐。
int length =(pq->rear-pq->front+MAXSIZE)%MAXSIZE;
// 第一个maxsize 防止负数的影响
//第二个maxsize 防止正数的多加
return length;
}
///
bool isempty(PQueue pq){
return pq->front==pq->rear;
}
bool isfull(PQueue pq){
return (pq->rear+1)%MAXSIZE ==pq->front;
}
void clear(PQueue pq)
{
pq->front=pq->rear =0;
}
void Destory(PQueue pq)
{
free(pq->base);
pq->base=NULL;
pq->front=pq->rear=0;
}
循环队列测试用例
void ahow(PQueue pq)
{
for(int i=pq->front;i!=pq->rear;i=(i+1)%MAXSIZE)
{printf("%d",pq->base[i]);}
printf("\n");
}
int main(){
Queue pq;
for(int i;i<20;i++)
{
Push(&pq,i+1);
show(&pq);
}
//后面的根据各位想法
return 0;
}
总结
为了使队列的时间复杂度降低,臆想其为环型。
但环型带来的判空判满问题也要进行进一步处理,来浪费部分空间做标记。
此外对于有效个数的求解也有十足的理解难度,但胜在简洁。两个maxsize的使用更是比较重要,诸位注意理解。
不足和错误之处诸位多多包涵。 天予不取,反受其咎,与诸君共勉。