第 3 章 栈和队列(单链队列)

news2025/4/12 9:01:22

1. 背景说明

队列(queue)是一种先进先出(first in first out,缩为 FIFO)的线性表。它只允许在表的一端进行插入,而在另一端删除元素。

2. 示例代码

1)status.h

/* DataStructure 预定义常量和类型头文件 */

#ifndef STATUS_H
#define STATUS_H

/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
#define ERR_NULL_QUEUE			9			/* 队列为空错 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2) linkQueue.h

/* 单链队列 —— 队列的链式存储结构头文件 */

#ifndef LINKQUEUE_H
#define LINKQUEUE_H

#include "status.h"

typedef int QElemType;

typedef struct QNode {
	QElemType data;
	struct QNode *next;
} QNode, *QueuePtr;

typedef struct {
	QueuePtr front, rear;
} LinkQueue;

/* 构造一个空队列 Q */
Status InitQueue(LinkQueue *Q);

/* 销毁队列 Q(无论空否均可) */
Status DestroyQueue(LinkQueue *Q);

/* 将 Q 清为空队列 */
Status ClearQueue(LinkQueue *Q);

/* 若 Q 为空队列,则返回 TRUE,否则返回 FALSE */
Bollean QueueEmpty(const LinkQueue *Q);

/* 求队列的长度 */
int QueueLength(LinkQueue *Q);

/* 若队列不空,则用 e 返回 Q 的队头元素,并返回 OK, 否则返回 ERROR */
Status GetQueueHead(const LinkQueue *Q, QElemType *e);

/* 插入元素 e 为 Q 的新的队尾元素 */
Status EnQueue(LinkQueue *Q, QElemType e);

/* 若队列不空,删除 Q 的队头元素,用 e 返回其值,并返回 OK, 否则返回 ERROR */
Status DeQueue(LinkQueue *Q, QElemType *e);

/* 从队头到队尾依次对队列 Q 中每个元素调用函数 vi() */
Status QueueTraverse(const LinkQueue *Q, void(*vi)(QElemType));

#endif // !LINKQUEUE_H

3) linkQueue.c

/* 单链队列 —— 队列的链式存储结构源文件 */

#include "linkQueue.h"
#include <stdio.h>
#include <stdlib.h>

/* 构造一个空队列 Q */
Status InitQueue(LinkQueue *Q)
{
	Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
	if (!Q->front) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	Q->front->next = NULL;

	return RET_OK;
}

/* 销毁队列 Q(无论空否均可) */
Status DestroyQueue(LinkQueue *Q)
{
	while (Q->front) {
		Q->rear = Q->front->next;
		free(Q->front);
		Q->front = Q->rear;
	}

	return RET_OK;
}

/* 将 Q 清为空队列 */
Status ClearQueue(LinkQueue *Q)
{
	Q->rear = Q->front;
	QueuePtr p = Q->front->next;
	Q->front->next = NULL;
	QueuePtr q = NULL;
	while (p) {
		q = p;
		p = p->next;
		free(q);
	}

	return RET_OK;
}

/* 若 Q 为空队列,则返回 TRUE,否则返回 FALSE */
Bollean QueueEmpty(const LinkQueue *Q)
{
	return (Q->front == Q->rear) ? TRUE : FALSE;
}

/* 求队列的长度 */
int QueueLength(LinkQueue *Q)
{
	int length = 0;
	QueuePtr p = Q->front;
	while (p != Q->rear) {
		++length;
		p = p->next;
	}

	return length;
}

/* 若队列不空,则用 e 返回 Q 的队头元素(队头元素为 front 的下一个元素), 并返回 OK, 否则返回 ERROR */
Status GetQueueHead(const LinkQueue *Q, QElemType *e)
{
	if (Q->front == Q->rear) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_QUEUE);
		return ERR_NULL_QUEUE;
	}

	*e = Q->front->next->data;

	return RET_OK;
}

static QueuePtr MakeNewQueueNode(QElemType e)
{
	QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
	if (!p) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return NULL;
	}

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

	return p;
}

/* 插入元素 e 为 Q 的新的队尾元素 */
Status EnQueue(LinkQueue *Q, QElemType e)
{
	QueuePtr p = MakeNewQueueNode(e);
	if (p == NULL) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PTR);
		return ERR_NULL_PTR;
	}

	Q->rear->next = p;
	Q->rear = p;

	return RET_OK;
}

/* 若队列不空,删除 Q 的队头元素,用 e 返回其值,并返回 OK, 否则返回 ERROR */
Status DeQueue(LinkQueue *Q, QElemType *e)
{
	if (Q->front == Q->rear) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_QUEUE);
		return ERR_NULL_QUEUE;
	}

	QueuePtr p = Q->front->next;
	*e = p->data;
	Q->front->next = p->next;
	if (Q->rear == p) {
		Q->rear = Q->front;
	}

	free(p);

	return RET_OK;
}

/* 从队头到队尾依次对队列 Q 中每个元素调用函数 vi() */
Status QueueTraverse(const LinkQueue *Q, void(*vi)(QElemType))
{
	QueuePtr p = Q->front->next;
	while (p) {
		vi(p->data);
		p = p->next;
	}

	return RET_OK;
}

4) auxiliary.h

/* 辅助函数头文件 */

#ifndef AUXILIARY_H
#define AUXILIARY_H

#include "linkQueue.h"

/* 打印栈元素 */
void Print(QElemType e);

#endif // !AUXILIARY_H

5) auxiliary.c

/* 辅助函数实现源文件 */

#include "auxiliary.h"
#include <stdio.h>

/* 打印栈元素 */
void Print(QElemType e)
{
	printf("%d ", e);
}

6) main.c

/* 入口程序源文件 */

#include "status.h"
#include "auxiliary.h"
#include "linkQueue.h"
#include <stdio.h>

int main(void)
{
	LinkQueue Q;
	Status ret = InitQueue(&Q);
	if (ret == RET_OK) {
		printf("Initialize queue success!\n");
	}

	printf("The queue is %s\n", (QueueEmpty(&Q) == TRUE) ? "empty" : "not empty");
	printf("The length of the queue is %d\n", QueueLength(&Q));
	EnQueue(&Q, -5);
	EnQueue(&Q, 5);
	EnQueue(&Q, 10);
	printf("After insert 3 elements, the length of the queue is %d\n", QueueLength(&Q));
	printf("The queue is %s\n", (QueueEmpty(&Q) == TRUE) ? "empty" : "not empty");
	printf("The elements of the queue is: ");
	QueueTraverse(&Q, Print);
	printf("\n");
	QElemType e;
	ret = GetQueueHead(&Q, &e);
	if (ret == RET_OK) {
		printf("The element of the head of the queue is %d\n", e);
	}

	DeQueue(&Q, &e);
	printf("Delete the element of the head of the queue %d\n", e);
	ret = GetQueueHead(&Q, &e);
	if (ret == RET_OK) {
		printf("The new element of the head of the queue is %d\n", e);
	}

	ClearQueue(&Q);
	printf("After clear the queue, Q.front = %p, Q.rear = %p, Q.front->next = %p\n",
		Q.front, Q.rear, Q.front->next);
	DestroyQueue(&Q);
	printf("After destroy the queue, Q.front = %p, Q.rear = %p\n", Q.front, Q.rear);

	return 0;
}

3. 输出示例

注意:free() 函数的作用并不仅仅把内存释放,还将指针置为空。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/965653.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

线上问诊:数仓开发(二)

系列文章目录 线上问诊&#xff1a;业务数据采集 线上问诊&#xff1a;数仓数据同步 线上问诊&#xff1a;数仓开发(一) 线上问诊&#xff1a;数仓开发(二) 文章目录 系列文章目录前言一、DWS1.最近1日汇总表1.交易域医院患者性别年龄段粒度问诊最近1日汇总表2.交易域医院患者…

身份识别与鉴权技术调研方案

对称加密算法 对称加密方式又称为私钥加密方式&#xff0c;该方式的加密和解密过程使用同一个密钥&#xff0c;因此该密钥又称为共享密钥。如图2.2所示&#xff0c;在对称加密方式中&#xff0c;发送方使用对称加密算法和共享密钥处理原始数据&#xff0c;得到一个加密后的密文…

vulnhub渗透测试靶场练习2

靶场介绍 靶场名&#xff1a;easy_cloudantivirus 靶场地址&#xff1a;https://www.vulnhub.com/entry/boredhackerblog-cloud-av,453 环境搭建 依旧使用VM VirtualBox搭建靶场&#xff0c;攻击机使用的是VMware中的kali&#xff0c;需要将VMware虚拟机kali和virtualbox靶机…

Web服务器部署上线踩坑流程回顾

5月份时曾部署上线了C的Web服务器&#xff0c;温故而知新&#xff0c;本篇文章梳理总结一下部署流程知识&#xff1b; 最初的解决方案&#xff1a;https://blog.csdn.net/BinBinCome/article/details/129750951?spm1001.2014.3001.5501后来的解决方案&#xff1a;https://blog…

Mysql数据库(3)—架构和日志

Mysql的架构设计 Mysql分为Server层和存储引擎层&#xff1a; Server层 主要包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&#xff08;如日期、时间、数学和加密函数等&#xff09;&#xff…

Android逆向学习(一)vscode进行android逆向修改并重新打包

Android逆向学习&#xff08;一&#xff09;vscode进行android逆向修改并重新打包 写在前面 其实我不知道这个文章能不能写下去&#xff0c;其实我已经开了很多坑但是都没填上&#xff0c;现在专利也发出去了&#xff0c;就开始填坑了&#xff0c;本坑的主要内容是关于androi…

回归拟合 | 灰狼算法优化核极限学习机(GWO-KELM)MATLAB实现

这周有粉丝私信想让我出一期GWO-KELM的文章&#xff0c;因此乘着今天休息就更新了(希望不算晚) 作者在前面的文章中介绍了ELM和KELM的原理及其实现&#xff0c;ELM具有训练速度快、复杂度低、克服了传统梯度算法的局部极小、过拟合和学习率的选择不合适等优点&#xff0c;而KEL…

OpenCV(十):图像缩放、翻转、拼接的介绍与使用

目录 &#xff08;1&#xff09;图像缩放&#xff1a;resize() &#xff08;2&#xff09;图像翻转&#xff1a; flip() &#xff08;3&#xff09;图像拼接&#xff1a;hconcat() 和vconcat() &#xff08;1&#xff09;图像缩放&#xff1a;resize() 使用 cv2.resize() 函…

React笔记(三)类组件(1)

一、组件的概念 使用组件方式进行编程&#xff0c;可以提高开发效率&#xff0c;提高组件的复用性、提高代码的可维护性和可扩展性 React定义组件的方式有两种 类组件&#xff1a;React16.8版本之前几乎React使用都是类组件 函数组件:React16.8之后&#xff0c;函数式组件使…

北京APP外包开发团队人员构成

下面是一个标准的APP开发团队构成&#xff0c;但具体的人员规模和角色可能会根据项目的规模和需求进行调整。例如&#xff0c;一些小型项目或初创公司可能将一些角色合并&#xff0c;或者聘请外包团队来完成部分工作。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公…

使用rabbitmq进行支付之后的消息通知

订单服务完成支付后将支付结果发给每一个与订单服务对接的微服务&#xff0c;订单服务将消息发给交换机&#xff0c;由交换机广播消息&#xff0c;每个订阅消息的微服务都可以接收到支付结果. 微服务收到支付结果根据订单的类型去更新自己的业务数据。 相关技术方案 使用消息…

【LeetCode】85.最大矩形

题目 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [["1","0","1","0","0"],["1&quo…

11. 微积分 - 偏导数方向导数

文章目录 偏导数方向导数方向余弦投影继续讲方向导数Hi, 大家好。我是茶桁。 我们上节课学习了链式法则,本节课,我们要学习「偏导数」和「方向导数」。 偏导数 偏导数在导论课里面也提到过。偏导数针对多元函数去讲的。 多元函数是什么,我们拿个例子来看: 多元函数: y…

springboot配置ym管理各种日记(log)

1&#xff1a;yml配置mybatis_plus默认日记框架 mybatis-plus:#这个作用是扫描xml文件生效可以和mapper接口文件使用&#xff0c;#如果不加这个,就无法使用xml里面的sql语句#启动类加了MapperScan是扫描指定包下mapper接口生效&#xff0c;如果不用MapperScan可以在每一个mapp…

2023.9.2 关于 JVM 垃圾回收机制(GC)

目录 为什么要有垃圾回收机制? STW&#xff08;Stop The World&#xff09;问题 垃圾回收机制主要回收哪个内存区域? 垃圾对象判断算法 引用计数算法 可达性分析算法 垃圾对象回收算法 标记清除算法 复制算法 标记整理算法 分代算法 为什么要有垃圾回收机制? 自动…

thinkphp中使用Elasticsearch 7.0进行多表的搜索

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、thinkphp中使用Elasticsearch 7.0进行多表的搜索二、使用步骤1.引入库2.读入数据 总结 前言 提示&#xff1a;thinkphp中使用Elasticsearch 7.0进行多表的…

stable diffusion实践操作-批次出图

系列文章目录 stable diffusion实践操作 文章目录 系列文章目录前言一、批次出图介绍1.1 webUI设置1.2 参数介绍 二、批次出图使用2.1 如何设置2.1 效果展示 总结 前言 本章主要介绍SD批次出图。 想要一次产生多张图片的时候使用。 一、批次出图介绍 1.1 webUI设置 1.2 参数…

[管理与领导-65]:IT基层管理者 - 辅助技能 - 4- 乌卡时代(VUCA )

前言&#xff1a; 大多数IT人&#xff0c;很勤奋&#xff0c;但都没有职业规划&#xff0c;被工作驱动着前行&#xff0c;然而&#xff0c;作为管理者&#xff0c;你就不能没有职业规划思维&#xff0c;因为你代表一个团队&#xff0c;你的思维决定了一个团队的思维。本文探讨…

2023-9-2 染色法判定二分图

题目链接&#xff1a;染色法判定二分图 #include <iostream> #include <cstring> #include <algorithm>using namespace std;const int N 100010l, M 200010;int n, m; int h[N], e[M], ne[M], idx;int color[N];void add(int a, int b) {e[idx] b, ne[id…

CSS中border-radius的来美化table的实战方案

border-radius是一种CSS属性&#xff0c;用于设置元素的边框的圆角程度。其具体的用法如下&#xff1a; 设置一个值&#xff1a;可以为元素设置一个单一的圆角半径&#xff0c;这个半径将应用于元素的四个角。例如&#xff1a; div {border-radius: 10px; }设置四个值&#x…