数据结构-栈、队列-详解

news2024/9/23 15:28:55

数据结构-栈、队列-详解

  • 1.前言
  • 2.
    • 2.1是什么
    • 2.2函数实现
      • struct Stack
      • StackInit
      • StackDestroy
      • StackPush
      • StackSize
      • StackEmpty
      • StackTop
      • StackPop
    • 2.3小结
  • 3.队列
    • 3.1是什么
    • 3.2函数实现
      • struct Queue
      • QueueInit
      • QueueDestroy
      • QueueEmpty
      • QueuePush
      • QueuePop
      • QueueFront
      • QueueBack
      • QueueSize
    • 3.3小结

1.前言

在数据结构中,队列都是一种线性表,但是,不同于顺序表和链表,栈和队列在对数据进行处理时,对数据的位置有特殊的规定。

2.

操作系统中,栈指的是内存的一块空间,用于存储函数、临时变量等。
这里的栈是一种数据结构
两个栈属于不同的学科,注意区分。

2.1是什么

栈(stack)是一种运算受限的线性表。限定仅在一端进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。
在这里插入图片描述

简单来说,对栈的操作和下图类似,都是后进去的先出来。

  • LIFO(Last In First Out)
    在这里插入图片描述

2.2函数实现

struct Stack

想要实现栈,首先创造的还是一个结构体,用于存储不同类型的变量。
而,高中生物老师讲过,结构与功能相对应,这里也是相同的道理。
为了便于对栈顶的数据进行处理,创造变量记下栈顶的位置top
其他的类比动态顺序表就行。

typedef char StackDataType;
typedef struct Stack
{
	StackDataType* a;
	int top;
	int capacity;
}Stack;

StackInit

栈的初始化。

void StackInit(Stack* s)
{
	assert(s);
	s->a = (StackDataType*)malloc(sizeof(StackDataType) * 4);
	if (!s->a)
	{
		perror("InitStack::malloc");
		return;
	}
	s->top = 0;
	s->capacity = 4;
}

这里主要问题是top的初始值,我选择的是0,用于表示栈顶下一个元素的下标
也可以是-1,用于表示栈顶元素的下标
当然,也可以是任意值,只要不嫌麻烦。

StackDestroy

栈的销毁。

void StackDestroy(Stack* s)
{
	assert(s);
	free(s->a);
	s->a = NULL;
	s->top = 0;
	s->capacity = 0;
}

StackPush

插入新元素,即压栈。

void StackPush(Stack* s,StackDataType x)
{
	assert(s);
	if (s->top == s->capacity)
	{
		StackDataType* tmp = (StackDataType*)realloc(s->a, sizeof(StackDataType)*s->capacity * 2);
		if (!tmp)
		{
			perror("PushStack::realloc");
			return;
		}
		s->a = tmp;
		s->capacity *= 2;
	}
	s->a[s->top] = x;
	s->top++;
}

需注意,我的top为栈顶下一个元素的下标,因此s->a[s->top] = x;
初始化不同时,此处操作应该也不同。

StackSize

元素个数。

int StackSize(Stack* s)
{
	assert(s);
	return s->top;
}

StackEmpty

判空。

bool StackEmpty(Stack* s)
{
	assert(s);
	return s->top == 0;
}

这个就比较有意思了,判空。
有人说,top == 0不就空了吗,为什么非要写个函数。
这里还是初始化的问题,如果top一开始是-1呢?
因此,让初始化top的人写个判空的函数,可减少意外发生。

StackTop

取栈顶元素,但不删除。

StackDataType StackTop(Stack* s)
{
	assert(s);
	assert(!StackEmpty(s));
	return s->a[s->top - 1];
}

StackPop

删除栈顶元素,即出栈。
一般与StackTop配合使用。

void StackPop(Stack* s)
{
	assert(s);
	assert(!StackEmpty(s));
	s->top--;
}

2.3小结

嗯。


可以试试这道题:有效的括号
思路:遇到左括号,压入栈;遇到右括号,与栈顶元素匹配,然后出栈。
我写的:(注:上面栈的数据结构CV过去就行)
在这里插入图片描述

3.队列

3.1是什么

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。

入队
...
A
B
C
D
....
出队

与栈的后入先出不同,队列为先入先出:
在这里插入图片描述
???

3.2函数实现

struct Queue

结构与功能相对应:

  • 队列在一边删除,另一边插入,使用顺序表会涉及挪动,浪费时间。因此,选择链表。
  • 使用双链表固然可以,但在这里没必要,虽然,双链表提供了额外的功能,但,使用单链表已经足够满足需求。因此,使用单链表。
  • 队列涉及队首和队尾的操作,因此,存储这两个结点可避免遍历链表。

于是,可以写出:

typedef int QDatatype;

typedef struct QueueNode
{
	struct QueueNode* next;
	QDatatype data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

QueueInit

初始化。

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

QueueDestroy

销毁。

void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}

QueueEmpty

判空。

bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}

QueuePush

入队:

void QueuePush(Queue* pq, QDatatype x)
{
	assert(pq);
	
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (!newnode)
	{
		perror("QueuePush::malloc");
		return;
	}
	newnode->next = NULL;
	newnode->data = x;
	
	if (!QueueEmpty(pq))
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	else
		pq->head = pq->tail = newnode;
		
	pq->size++;
}

QueuePop

出队。

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	QNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	if (pq->head == NULL)
		pq->tail = NULL;
	pq->size--;
}

需注意,当变为空队列时,需把tail也置空。

QueueFront

获取队首元素。

QDatatype QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

QueueBack

获取队尾元素。

QDatatype QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

QueueSize

获取队伍长度。

int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

3.3小结

最主要的问题集中于如何定义结构,当队列的结构体创建好后,其他函数实现并不复杂。


希望本篇文章对你有所帮助!并激发你进一步探索数据结构的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!

相关文章:
数据结构-顺序表-详解
数据结构-单链表-详解-1
数据结构-单链表-详解-2

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

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

相关文章

Verilog基础,原码,反码与补码的概念

Verilog模块初认识 1、Verilog模块(Module) Verilog中的module可以看成一个具有输入输出端口的黑盒子,该黑盒子有输入和输出接口(信号),通过把输入在盒子中执行某些操作来实现某项功能。(类似于C语言中的函数) 图1 模块示意图 1.1 模块描述 图1 所示的…

【408DS算法题】035进阶-17年真题_二叉树转中缀表达式

Index 真题题目分析实现总结 真题题目 请设计一个算法,将给定的表达式树(二叉树)转换为等价的中缀表达式(通过括号反映操作符的计算次序)并输出。 例如, 当下列两棵表达式树作为算法的输入时, …

vivado 定义约束设置和文件

步骤2:定义约束集和文件 首先创建一个新的约束集,并向其中添加一个空的XDC约束文件 示例设计已经包含两个约束集,但您没有在本实验室中使用它们。 1.在“流导航器”中,单击“项目管理器”部分中的“添加源”。 2.从“添加源”对话…

【自考zt】【软件工程】【21.10】

关键字: 软件需求基本性质、软件系统需求挑战、耦合(高内容,低无直接)、内聚(初始化时间)、uml包、rup边界类、测试首要目标、单元测试最后工作、性能需求 软件开发本质、软件需求规约三种风格、提炼、用…

windows C++ 并行编程-并发和UWP(二)

下面例程用于演示在UWP中进行并发编程。 示例: 创建 C Windows 运行时组件并从 C# 中使用它 假设有一个使用 XAML 和 C# 的应用,可用它来定义 UI 和 C Windows 运行时组件以执行计算密集型操作。 在此示例中,C 组件会计算给定范围中的哪些数字是质数。…

Sqoop 数据迁移

Sqoop 数据迁移 一、Sqoop 概述二、Sqoop 优势三、Sqoop 的架构与工作机制四、Sqoop Import 流程五、Sqoop Export 流程六、Sqoop 安装部署6.1 下载解压6.2 修改 Sqoop 配置文件6.3 配置 Sqoop 环境变量6.4 添加 MySQL 驱动包6.5 测试运行 Sqoop6.5.1 查看Sqoop命令语法6.5.2 测…

Maven与Gradle差异

作为Java 开发者,你平时用 Maven 还是 Gradle? 我一直用的都是 Maven,但是前几天做了一个小项目,用的是 Gradle,因工作需要就去了解了Gradle的相关信息。 直到看到 Spring 和 Spring Boot 都从 Maven 切换到 Gradle了…

鸿蒙界面开发——组件(4):图标小符号 (SymbolGlyph/SymbolSpan) 气泡提示Popup

SymbolGlyph 创建图标 SymbolGlyph通过引用Resource资源来创建,资源引用类型可以通过$r创建Resource类型对象。不支持子组件。 SymbolGlyph(value?: Resource)SymbolGlyph($r(sys.symbol.ohos_folder_badge_plus)).fontSize(96).renderingStrategy(SymbolRenderi…

【GD32】---- 使用GD32调试串口并实现printf打印输出

1 复制工程模板 直接复制工程模板里的系统文件和固件库文件到新的工程文件01_USART_Printf 2 新建keil工程 参考上一篇博文:【GD32】---- 移植工程模板及点灯测试 3 编写代码 3.1 创建USART文件 创建一个USART.c文件,放于05_UserDriver文件夹中 …

macOS安装Maven

安装Java Java Downloads | Oracle 官网下载默认说最新的Java22版本,注意这里我们要下载的是Java8,对应的JDK1.8 需要登陆Oracle,没有账号的可以百度下。账号:908344069qq.com 密码:Java_2024 Java8 jdk1.8配置环境变量 open -e ~/.bash_p…

关于edge浏览器登陆CSDN安全验证不跳出验证码

前言 也就是最近这几天才出现这个问题,以前用edge浏览器登陆csdn时即使需要安全验证也能正常弹出验证码,现在根本没反应。 正文 我用edge浏览器登陆时,显示如下界面,就卡住不动了。 起初我以为是我浏览器可能设置了拦截的问题…

数据分析利器:Java与MySQL构建强大的数据挖掘系统

数据分析在当今信息时代具有重要的作用,它可以帮助企业和组织深入理解数据,发现隐藏在数据中的模式和规律,并基于这些洞察进行决策和优化。Java与MySQL作为两个强大的工具,结合起来可以构建出一个高效、可靠且功能丰富的数据挖掘系…

《中文Python穿云箭量化平台二次开发技术09》设计一个可视化股票池量化平台项目用于实现选股和自动交易

《中文Python穿云箭量化平台》是纯Python开发的量化平台,因此其中很多Python模块,我们可以自己设计新的量化工具,例如自己新的行情软件、新的量化平台、以及各种量化研究工具。 穿云箭自带指标公式源码运行模块,可以为其他量化平台…

ROS/ROS2版本和Gazebo版本

简洁版本: ROS Noetic Gazebo 11 (ubuntu 20.04)ROS Jazzy Gazebo Harmonic (ubuntu 24.04) 其他版本搭配也可以学习和研究但是成本过高。 如何贯穿从ROS kinetic到ROS Jazzy的教程。 如何实现旧新的平滑过度。 …

python常用库学习-Matplotlib使用

文章目录 安装 Matplotlib导入库基本示例1. 绘制简单的线图2. 散点图3. 柱状图4. 直方图5. 子图 更多高级功能1. 自定义样式2. 文本和注释3. 保存图形 示例:使用 Matplotlib 绘制多个图表示例 1: 绘制多个线图示例 2: 绘制散点图和直方图 参考文献 Matplotlib 是 Py…

【QT】VS2020+QT插件 CMake项目开发踩坑记录

背景 我使用的是VS2022, 安装了QT的两个插件,并且使用CMake进行工程管理。 当然如果你想通过VS开发qt,第一步是安装QT(我目前安装了最新的6.7版本) 然后才是安装VS中的QT插件。 这篇文章,主要记录&#x…

Navicat出了免费版本

官方下载地址 Navicat出了一款免费版本Navicat Premium Lite,相比正常版本阉割了很多功能,最让人无奈的是没有美化sql功能。 可以满足我们的日常需求,提供了基础的功能:创建连接、连接分组、管理表、管理数据、导入导出数据。还…

台球助教APP小程序的前端交互设计

在当今移动互联网时代,台球助教APP小程序作为一种便捷的学习工具,正在成为越来越多台球爱好者的首选。作为设计人员,在开发台球助教APP小程序时,我们的目标是创造一个既美观又实用的应用程序,让用户在使用过程中感到舒…

VS编译环境中printf() scanf()等文件操作函数不安全编译报错的解决方法

如题,在使用诸如printf() scanf() fopen()等函数时会出现如下图这样不安全的错误 解决方法: 在程序的前面添加此预编译指令 #pragma warning(disable:4996) 添加后即可编译通过。

基于vue框架的超市管理系统yqogz(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:用户,商品分类,商品信息,员工,进货信息 开题报告内容 基于Vue框架的超市管理系统开题报告 一、研究背景与意义 随着信息技术的飞速发展和零售行业的数字化转型,超市作为传统零售业的重要组成部分,面临着提升管…