当前位置: 首页 > article >正文

数据结构-队列

目录

概念

队列的抽象数据类型定义

队列的顺序表示 

假溢出 

解决假溢出-循环队列

新的问题 

队列满的条件思考 

队列长度计算公式

队列的顺序实现

队列的元素类型定义

队列的初始化

求队列的长度 

循环队列入队 

循环队列出队

队列的链式表示和实现

链队列的类型定义

Qnode是什么

LinkQueue是什么

链队的入队操作

链队的出队操作 


概念

  • 队列(queue)是一种先进先出(Frist In Frist Out)的线性表,简称FIFO结构
  • 在表一端插入(表尾,即aₙ端,称为队尾),在另一端(表头,即a₁端,称为队头)删
  • 插入元素称为入队,删除元素称为出队


队列的抽象数据类型定义

ADT Queue{

        数据对象:D = {aᵢ | aᵢ∈ElemSet, i = 1,2,...,n,n >= 0}

        数据关系:R = {<aᵢ₋₁,aᵢ> | aᵢ₋₁,aᵢ∈D,i = 2,...,n}  // 约定其中a₁端为队列头,aₙ端为队列尾

        基本操作:

        InitQueue(*Q)

        操作结果:构造一个空队列Q

        DestoryQueue(*Q)

        条件:队列Q已存在

        操作结果:销毁Q

        ClearQueue(*Q)

        条件:队列Q已存在

        操作结果:将Q清空

        QueueEmpty(Q)

        条件:Q已存在

        操作结果:若队列Q为空,返回TRUE;否则返回FALSE

        GetHead(Q, *e)

        条件:Q已存在且非空

        操作结果:用e返回Q的队头元素

        QueueLength(Q)

        条件:Q已存在

        操作结果:返回Q的元素个数,即队长

}ADT Queue


队列的顺序表示 

  • 引入两个指针
    • front指针指向队头
    • rear指针指向队尾元素的下一个位置
  • 空队列:front == rear

假溢出 

如:

  • 这个队列的总个数不超过5个,front指针指向下标为2的位置,继续入队,就会产生数组越界的错误
  • 可实际上,我们的队列在下标为0和1的地方还是空闲的,这种现象叫作“假溢出”

解决假溢出-循环队列

  • 解决假溢出的办法就是,后面满了,就再从头开始,也就是头尾相接的循环
  • 我们把队列的这种头尾相接的称为循环队列
  • 使用刚才的例子,将rear改为指向下标为0的位置,就不会造成指针指向不明的问题了


  • 接着再入队a₆、a₇

新的问题 

  • 空队列时,front == rear
  • 现在的循环结构,当队列满时,也是fornt == rear
  • 此时如何判断?

  • 当队列空时,front == rear,当队列满时,我们修改其条件,保留一个元素空间
  • 也就说,队列满时,数组中其实还有一个空间单元
  • 两副图都表示队列满时


队列满的条件思考 

  • 队列的最大尺寸为MAXQSIZE
  • 队列满的条件是:(rear + 1) % MAXQSIZE == front

  • 此时,front = 0,rear = 4,(4 + 1) % 5 = 0,此时队列满

  • 此时,front = 2,rear = 1,(1 + 1) % 5 = 2,此时队列满

队列长度计算公式

通用的计算队列长度公式:(rear - front +MAXQSIZE) % MAXQSIZE

  • 当rear > front时
  • 队列的长度为rear - front



  • 当rear < front时
  • 队列长度分为两段
    • 一段是MAXQSIZE - front 
    • 一段是0 + rear
  • 加在一起,队列长度:rear - front + MAXQSIZE


队列的顺序实现

队列的元素类型定义

typedef struct
{
	QElemType* base;  // 初始化的动态分配存储空间
	int front;  // 头指针
	int rear;  // 尾指针,若队列不空,指向队列尾元素的下一个位置
}SqQueue;


队列的初始化

Status InitQueue(SqQueue* Q)
{

    /* 结构定义中使用了动态分配存储空间,需要分配数组空间 */
	Q->base = new QElemType[MAXQSIZE];

	if (!Q->base)exit(OVERFLOW);  // 存储分配失败
	
	// 头指针尾指针置为0,队列为空
	Q->front = 0;
	Q->rear = 0;  

	return OK;
}


求队列的长度 

int QueueLength(SqQueue Q)
{
	return ((Q.rear - Q.front + MAXQSIZE) % MAXQSIZE);
}


循环队列入队 

Status EnQueue(SqQueue* Q, QElemType e)
{
	// 判断队满
	if ((Q->rear + 1) % MAXQSIZE == Q->front) return ERROR; 
	
	// 新元素赋值给队尾
	Q->base[Q->rear] = e;  

	/* 
	队尾指针向后移一位置
	若到最后则转到数组头部
	*/
	Q->rear = (Q->rear + 1) % MAXQSIZE; 

	return OK;
}


循环队列出队

Status DeQueue(SqQueue* Q, QElemType* e)
{
	// 判断队空
	if (Q->front == Q->rear)return ERROR;

	// 将队头元素赋值给e
	*e = Q->base[Q->front];  

	/*
	队头指针向后移一位置
	若到最后则转到数组头部
	*/
	Q->front = (Q->front + 1) % MAXQSIZE; 

	return OK;
}

队列的链式表示和实现

若用户无法估计所用队列的长度,则采用链队列 

链队列的类型定义

/* 结点的结构 */
typedef struct Qnode 
{
	QElemType data;
	struct Qnode* next;
}QNode, *QueuePtr;

/* 队列的链表结构 */
typedef struct
{
	QueuePtr front;  // 队头指针
	QueuePtr rear;  // 队尾指针
}LinkQueue;

Qnode是什么

  • struct Qnode:这是一个结构体类型,它定义了链队列中的一个节点,包含数据部分 data 和指向下一个节点的指针 next
  • QNode:这是 struct Qnode 的一个别名。在C语言中,当你使用 typedef 为结构体定义了一个新名字后,你可以使用这个新名字来声明该类型的变量。例如,你可以使用 QNode node; 来创建一个节点变量(等价于struct Qnode node;
  • *QueuePtr:这是一个指向 struct Qnode 类型的指针的别名。它定义了一个指针类型,该类型指向 Qnode 结构体。在代码中,你可以使用 QueuePtr 来声明指向节点的指针变量,例如 QueuePtr ptr;(等价于struct Qnode* ptr; )

LinkQueue是什么

  • 这次定义的是 LinkQueue 类型,它用于表示整个链队列
  • QueuePtr front;:这是 LinkQueue 结构体的一个成员,它是一个指向 Qnode 的指针,表示队列的头部
  • QueuePtr rear;:这是 LinkQueue 结构体的另一个成员,它也是一个指向 Qnode 的指针,表示队列的尾部

链队的入队操作

入队操作时,其实就是在链表尾部插入结点


 

Status EnQueue(LinkQueue* Q, QElemType e)
{
	QueuePtr s = (QueuePtr)malloc(sizeof(QNode));

	// 存储分配失败
	if (!s) exit(OVERFLOW);

	s->data = e;
	s->next = NULL;

	// 把新结点s赋值给原队尾结点的后继
	Q->rear->next = s;

	// 把当前s设置为队尾结点,rear指向s
	Q->rear = s;

	return OK;
}


链队的出队操作 

  • 出队操作,就是头结点的后继结点出队,将头结点的后继改为它后面的结点
  • 若链表除头结点外只剩一个元素时,则需将rear指向头结点


http://www.kler.cn/news/366928.html

相关文章:

  • 【自然语言处理】BERT模型
  • ALIGN_ Tuning Multi-mode Token-level Prompt Alignment across Modalities
  • Linux:定时任务
  • 推荐15个 Vue 常用自定义指令,含实现原理与使用方式
  • 鸿蒙开发初级证书考试答案
  • RV1126音视频学习(二)-----VI模块
  • Vast.ai LLM 大语言模型使用手册(2)
  • 74. 搜索二维矩阵
  • 了解 - 微格式
  • 萤石设备视频接入平台EasyCVR私有化视频平台变电站如何实现远程集中监控?
  • Java后端面试题:Java基础篇
  • Spring微服务概述之spring cloud alibaba服务调用实践
  • 在平面模型上提取凹多边形的点云处理
  • Unity引擎:游戏开发的核心力量
  • python 深度学习 项目调试 图像分割 segment-anything
  • 微信小程序 - 动画(Animation)执行过程 / 实现过程 / 实现方式
  • RabbitMQ 发布确认高级部分
  • 语音交互:重塑人机对话的未来
  • 【Nas】X-Doc:jellyfin“该客户端与媒体不兼容,服务器未发送兼容的媒体格式”问题解决方案
  • 量子计算突破:下一个科技革命的风口浪尖在哪里?
  • Spring Boot 集成 PDFBox 实现PDF电子签章的简单应用
  • AI大模型开发架构设计(16)——ChatGPT Code Interpreter应用场景和技术原理动手实践
  • 【Python爬虫实战】Selenium自动化网页操作入门指南
  • 数据结构------手撕链表(一)【不带头单向非循环】
  • 掌握预测的准确性——使用 VAEneu 和 CRPS 的概率方法
  • PMP–一、二、三模–分类–11.风险管理–机会风险应对策略