学《数据结构》越学越聪明--第三章》》》栈和队列(二)队列

队列

队列的定义

队是一种只能从一端插入的线性表。队列只能选取一端进行插入操作,另一个端点进行删除操作

在这里插入图片描述

队列的概念

  • 插入的一端称为队尾(rear)

  • 删除的一端称为队头或队首(front)

  • 向队列中插入新的元素称为进对或入队,新元素进队后成为新的队尾元素。

  • 向队列中删除元素称为出队或离队,元素出队后其后继结点称为新的队首元素

在这里插入图片描述

队列的特点是先进先出,又把队列称为“先进先出表”

在这里插入图片描述

抽象数据类型=逻辑结构+基本运算(运算描述)

栈的几种基本运算如下:
  1. InitQueue(&q)初始化队列。构造一个空队列q

  2. DestroyQueue(&q)销毁队列。释放队列q所占的存储空间

  3. QueueEmpty(q)判断队列是否为空:若队列q为空,则返回真,否则返回假

  4. enQueue(&q,e)进队列,将元素e进队作为队尾元素

  5. deQueue(&q,&e)出队列,从队列q中出队一个元素,并将其值赋给e

在这里插入图片描述

队列中元素逻辑关系与线性表中的相同,队列可以采用与线性表相同的存储结构。
![在这里插入图片描述](https://img-blog.csdnimg.cn/703196fb6b4241ed833f3e6702dee418.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Zu35Yab55qE5bCP5a6d6LSd,size_20,color_FFFFFF,t_70,g_se,x_16)

思考

队列和线性表有什么不同?

队列和栈有什么不同?

队列的顺序存储结构及其基本运算的实现

顺序队
假设栈中的存储元素个数最大不超过正整数MaxSize个,所有元素类型都具有相同一数据类型ElemType,则可以用以下方式来定义顺序队类型SqQueue
typedef struct 
{
ElemType daat[MaxSize];
int front,rear; 	  //队首和队尾指针
}SqStack;
以为队的两端都在变化,所以需要两个指针来标识队列

在这里插入图片描述

小结
  • 约定rear总是指向队尾元素,元素进队rear+1;
  • 约定front总是指当前队中队头元素的前一位置,元素出队front+1
  • 当MaxSize=-1时不能再进队

在这里插入图片描述

顺序队的四要素

  1. 队空条件:front=rear

  2. 队满条件:rear=MaxSize-1

  3. 元素e进队操作:raar++;将元素e放入rear处,data[rear]=e

  4. 元素e出队操作:front++;将队首指针的值赋值给元素e e=data[front]

在这里插入图片描述

在顺序栈中实现栈基本运算的算法

InitQueue(&s)初始化队
建立一个新的队q,实际上是将队首指针front和队尾指针rear都等于-1;
void InitQueue(SqQueue*& q) {
	q = (SqQueue*)malloc(sizeof(SqQueue));
	q->front = q->rear = -1;
}
DestroyQueue(&s)销毁队列
释放队q的存储空间
//销毁队列
//释放队q的内存
void DestroyQueue(SqQueue*& q) {
	free(q);
}

QueueEmpty(s)判断队列是否为空
若满足q->rear==q->front返回真,否则假
//判断队列是否为空
//若满足q->rear==q->front返回真,否则假
bool QueueEmpty(SqQueue* q) {
	return (q->rear == q->front);
 }
enQueue(&s,e)进队
若队不满,让队尾指针rear循环增1,将元素e插入到rear所指的元素上
//进队
//若队不满,让队尾指针rear循环增1,将元素e插入到rear所指的元素上
void enQueue(SqQueue* q, ElemType e) {
	if (q->rear==MaxSize-1)return;
	q->rear++;
	q->data[q->rear] = e;
}
deQueue(&s,&e)出队
若队不为空,则让队首指针增1,然后将所指的元素赋值给e
//出队
//若队不为空,则让队首指针增1,然后将所指的元素赋值给e
void enQueue(SqQueue*&q, ElemType &e) {
	if (q->front == q->rear)return;
	q->front++;
	e = q->data[q->front];
}

环形队列(或循环队列)中实现队列的基本运算

在这里插入图片描述

解决方案

把数组的前端和后端链接起来,形成一个环形的顺序表,即把存储队列元素从逻辑上看作是一个环,称为环形队列或循环队列

在这里插入图片描述

如何实现
实际上内存地址一定是连续的,不可能是环形的,这里是通过逻辑方式实现环形队列,也就是将rear++和front++该为:
  • rear=(rear+1)%MaxSize

  • front=(front+1)%MaxSize

在这里插入图片描述

演示

在这里插入图片描述

环形队列四要素
  1. 队空条件rear=front

  2. 队满条件(rear+1)%MaxSize=front

  3. 元素e进队操作rear=(rear+1)%MaxSize;将e放在rear处

  4. 元素e出队操作fornt=(front+1)%MaxSize;取出front处元素e

在环形队列中,实现队列的基本运算算法与非环形队列类似,只是改为上述四要素即可。

在这里插入图片描述

环形队列的应用

对应环形队列来说,如果知道队头指针和队列中元素个数,则可以计算处队尾指针。
也就是说,可以用队列中元素个数代替队尾指针。

设计处这种环形队列的初始化、入队、出队和判空算法

在这里插入图片描述

已知front、rear求元素个数count? MaxSize=5

在这里插入图片描述
得出结论:

  • 已知front、rear,求队中元素个数count

    count(rear-front+MaxSize)%MaxSize

  • 已知front、count,求rear:

    rear=(front+count)%MaxSize

  • 已知rear,count求front

    front=(rear-count+MaxSize)%MaxSize

在这里插入图片描述

带元素个数的循环队列基本运算的算法

依题意设计的环形队列类型如下:
typedef struct {
	ElemType data[MaxSize];
	int front;   //队首指针
	int count;   //队列中元素个数
}QuType;

环形队列四要素
  1. 队空条件count=0

  2. 队满条件count=MaxSize

  3. 元素e进队操作rear=(rear+1)%MaxSize;将e放在rear处,count++

  4. 元素e出队操作fornt=(front+1)%MaxSize;取出front处元素e,count--

这样的环形队列最多可存放MaxSize个元素
InitQueue(&s)初始化队
建立一个新的队q,实际上是将队首指针front和队内元素个数都等于0;
void InitQueue(SqQueue*& qu) {
	qu = (SqQueue*)malloc(sizeof(SqQueue));
	qu->front = qu->count = 0;
}
EnQueue(&s,e)进队
若队不满,算出队尾指针,让队尾指针rear循环增1,将元素e插入到rear所指的元素上,对内元素count+1
//进队
bool EnQueue(QuType* &qu, ElemType e) 
{
	int rear;
	if (qu->count == MaxSize)return false;   //队满
	else {
		rear = (qu->count + qu->front) % MaxSize;  //求队尾位置
		rear = (rear + 1) % MaxSize;   //队尾+1
		qu->data[rear] = e;  //插入元素e
		qu->count++;   //队内元素+1
		return ture;
	}
}
DeQueue(&s,&e)出队
若队不为空,则让队首指针增1,然后将所指的元素赋值给e,队内元素个数count+1
//出队
bool DeQueue(QuType* &qu, ElemType &e) {
	if (qu->count == 0)return false;
	else {
		qu->front = (qu->front + 1) % MaxSize;
		e = qu->data[qu->front];
		qu->count--;
		return true;
	}
}
QueueEmpty(s)判空
//判空
bool QueueEmpty(QuType* qu) {
	return (qu->count==0);
}

注意

显然环形队列比非环形队列更有效率利用内存空间,即环形队列会重复使用已经出队元素的空间。不会出现假溢出

但如果算法中需要使用所以进队的元素来进一步求解此时可以使用非环形队列

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雷军的小宝贝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值