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

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() 函数的作用并不仅仅把内存释放,还将指针置为空。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Lua学习(一)

lua基础学习 LUA 语言1. 什么是lua&#xff1f;1.1 准备工作 2. 基本语法2.1 注释2.2 标识符2.3 关键字2.4 全局变量 3. 数据类型4. 变量4.1 赋值语句 5. 循环5.1 while循环5.2 for循环5.3泛型for循环5.4 repeat until 循环5.5 break 语句 6. 流程控制6.1 if语句6.2 if else 语…

动态规划之连续乘积最大子数组 连续和最大子数组

一. 连续和最大子数组 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,-5,…

【Apollo学习笔记】——规划模块TASK之SPEED_HEURISTIC_OPTIMIZER

文章目录 前言SPEED_BOUNDS_PRIORI_DECIDER功能简介SPEED_BOUNDS_PRIORI_DECIDER相关配置SPEED_BOUNDS_PRIORI_DECIDER流程1. 对路程和时间进行采样以及速度限制2. 设计状态转移方程&#xff08;cost计算&#xff09;2.0 CalculateCostAt代价计算2.1 GetObstacleCost障碍物cost…

[dasctf]misc04

与他不说一模一样吧也差不多 第三届红明谷杯CTF-【MISC】-阿尼亚_keepb1ue的博客-CSDN客flag.zip需要解压密码&#xff0c;在图片中发现一串密文。一串乱码&#xff0c;尝试进行字符编码爆破。获取到密码&#xff1a;简单的编码。https://blog.csdn.net/qq_36618918/article/d…

RobotFramework中的常用变量

文章目录 前言 一 标量&#xff0c;列表和字典1. Scalar 变量1.1 在变量文件&#xff08;Variables&#xff09;中使用1.2 在测试用例&#xff08;TestCases&#xff09;中使用1.3 Scalar 变量的相关操作 2. List 变量2.1 在变量文件&#xff08;Variables&#xff09;中使用2.…

【Redis从头学-完结】Redis全景思维导图一览!耗时半个月专为Redis初学者打造!

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

设计模式-7--代理模式(Proxy Pattern)

一、什么是代理模式&#xff08;Proxy Pattern&#xff09; 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许一个对象&#xff08;代理&#xff09;充当另一个对象&#xff08;真实对象&#xff09;的接口&#xff0c;以控制对该对象的…

Unity中Shader的遮罩的实现

文章目录 前言一、遮罩效果的实现主要是使用对应的纹理实现的&#xff0c;在属性中暴露对应的遮罩纹理&#xff0c;对其进行采样后&#xff0c;最后相乘输出即可二、如果需要像和主要纹理一样流动&#xff0c;则需要使用和_Time篇一样的方法实现流动即可 前言 Unity中Shader的…

企业网络安全:威胁检测和响应 (TDR)

什么是威胁检测和响应 威胁检测和响应&#xff08;TDR&#xff09;是指识别和消除 IT 基础架构中存在的恶意威胁的过程。它涉及主动监控、分析和操作&#xff0c;以降低风险并防止未经授权的访问、恶意活动和数据泄露&#xff0c;以免它们对组织的网络造成任何潜在损害。威胁检…

thinkphp6 入门(2)--视图、渲染html页面、赋值

修改模板引擎 config/view.php // 模板引擎类型使用Think type > php, 2. 新建一个控制器 本文app的名称为test&#xff0c;在其下新建一个控制器User app/test/controller/User.php 注意&#xff1a;需要引用think\facade\View来操作视图 <?phpnamespace app\te…

医学案例|线性回归

一、案例介绍 某医师预研究糖尿病患者的总胆固醇和甘油三酯对空腹血糖的影响&#xff0c;某研究者调查40名糖尿病患者的总胆固醇、甘油三酯和空腹血糖的测量值如下&#xff0c;试根据上述研究问题作统计分析。 二、问题分析 本案例想要研究一些变量&#xff08;总胆固醇和甘油…

软件架构Architecture篇卷首语

2023年9月2日&#xff0c;周六晚上 我为什么要开始学习软件架构&#xff1f;我为什么要专门开始这个专栏&#xff1f; 原因如下&#xff1a; Well-structured software is delivered in half the time, at half the cost, with 8x less bugs ——US Air Force study 这句话是我…

17.CSS发光按钮悬停特效

效果 源码 <!DOCTYPE html> <html> <head><title>CSS Modern Button</title><link rel="stylesheet" type="text/css" href="style.css"> </head> <body><a href="#" style=&quo…

Pygame中Trivia游戏解析6-4

3.3.3 显示题目选项 在显示题目选项时&#xff0c;有三种情况&#xff1a;分别是用户还未选择答案时&#xff1b;用户的答案是正确时&#xff1b;用户的答案是错误时。 &#xff08;1&#xff09;用户还未选择答案时 此时&#xff0c;用白色显示四个备选答案&#xff0c;如图…

Docker 网络模式

文章目录 一、Docker 网络实现原理1.容器的端口映射 二、Docker的网络模式1.Host模式2.Container模式3.none模式4.bridge模式 三、自定义网络1、查看网络模式列表2、查看容器信息(包含配置、环境、网关、挂载、cmd等等信息&#xff09;3、指定分配容器IP地址 面试题 一、Docker…

Python之分支-循环

Python之分支-循环 程序控制 顺序 按照先后顺序一条条执行。 a 1 b a 1 c max(a, b) d c 100 # 这是顺序执行分支 根据不同的情况判断&#xff0c;条件满足执行某条件下的语句。 if 真(True)真执行的语句体passpassif True:pass else:pass # 单分支if语句这行的最后…

【方案】基于视频与AI智能分析技术的城市轨道交通视频监控建设方案

一、背景分析 地铁作为重要的公共场所交通枢纽&#xff0c;流动性非常高、人员大量聚集&#xff0c;轨道交通需要利用视频监控系统来实现全程、全方位的安全防范&#xff0c;这也是保证地铁行车组织和安全的重要手段。调度员和车站值班员通过系统监管列车运行、客流情况、变电…

查询优化器内核剖析之查询的执行与计划的缓存 Hint 提示

本篇议题如下: 查询的执行与计划的缓存 Hint 提示 首先看到第一个议题 查询的执行与计划的缓存 一旦查询被优化之后&#xff0c;存储引擎就使用选中的执行计划将结果返回&#xff0c;而被使用的这个执行 计划就会被保存在内存中一个被称之为“计划缓存”的地方&#xff0c;从…

【负载均衡】常见的负载均衡策略有哪些?

文章目录 前言负载均衡分类常见负载均衡策略小结 前言 负载均衡策略是实现负载均衡器的关键&#xff0c;而负载均衡器又是分布式系统中不可或缺的重要组件。使用它有助于提高系统的整体性能、可用性、可靠性和安全性&#xff0c;同时支持系统的扩展和故障容忍性。对于处理大量…

Linux常用命令——cupsdisable命令

在线Linux命令查询工具 cupsdisable 停止指定的打印机 补充说明 cupsdisable命令用于停止指定的打印机。 语法 cupsdisable(选项)(参数)选项 -E&#xff1a;当连接到服务器时强制使用加密&#xff1b; -U&#xff1a;指定连接服务器时使用的用户名&#xff1b; -u&#…