【数据结构与算法】栈和队列(StackQueue)

news2024/11/20 11:43:40

@TOC

数据结构—栈

栈的概念

要想学习一个东西,概念是一定要看并且理解的,那么栈是个什么玩意呢?

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

可以用下图来理解,非常简单。

image-20230319191609052

其实也就是只有一个口是进元素和出元素的,进入元素叫做入栈,出去元素则叫出栈。由于其结构特性,所以总结为先进后出,或者叫做后进先出。

image-20230319191930993

以上就是栈的结构描述和基本了解。下面就该是栈的实现了。

栈的实现

由于栈只是提供了一种数据存储的思路,所以具体怎样来实现选择其实是并不确定的,通常来说栈的实现是通过数组或者链表实现,而数组实现的栈叫做顺序栈,链表实现的栈叫做链栈。通常来说,顺序栈比较好写一点,而且用起来其实比链栈也更优一些。比较一下两者结构,很容易发现由于链表并不适合尾插,所以数组在尾上插入数据的代价比较小

image-20230319193834000

这里我们就实现比较优的顺序栈了。

typedef int DateType;

typedef struct Stack
{
    DateType* arr;
    size_t top;//栈顶
    size_t capacity;//容量
}Stack;

//初始化栈
void StackInit(Stack* ps);
//销毁栈
void StackDestroy(Stack* ps);

//入栈
void StackPush(Stack* ps,DateType x);
//出栈
void StackPop(Stack* ps);

//获取栈顶元素
DateType StackTop(Stack* ps);
//获取栈的有效元素个数
size_t StackSize(Stack* ps);
//判断栈是否为空
bool StackEmpty(Stack* ps);

上面就是实现一个顺序栈要去完善的接口,栈相对于之前的链表来说实在是过于简单。

typedef int DateType;

typedef struct Stack
{
    DateType* arr;
    size_t top;//栈顶
    size_t capacity;//容量
}Stack;

//初始化栈
void StackInit(stack* ps)
{
	assert(ps);
	DateType* tmp = (DateType*)malloc(sizeof(DateType)*INITNUM);
	if (tmp == NULL)
	{
		perror("StackInit fail\n");
		return;
	}
	ps->arr = tmp;
	ps->capacity = INITNUM;//默认容量
	ps->top = 0;//栈顶的下一个下标
}

//销毁栈
void StackDestroy(stack* ps)
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//入栈
void StackPush(stack* ps, DateType x)
{
	assert(ps);
	//检查容量是否需要扩容
	if (ps->capacity == ps->top)
	{
		DateType* tmp = (DateType*)realloc(ps->arr, sizeof(DateType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("StackPush fail\n");
			return;
		}
		ps->arr = tmp;
		ps->capacity *= 2;
	}

	ps->arr[ps->top++] = x;
}
//出栈
void StackPop(stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	ps->top--;
}

//获取栈顶元素
DateType StackTop(stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->arr[ps->top - 1];
}
//获取栈的有效元素个数
size_t StackSize(stack* ps)
{
	assert(ps);

	return ps->top;
}
//判断栈是否为空
bool StackEmpty(stack* ps)
{
	assert(ps);

	return ps->top == 0;
}

其实并不难对不对,其中需要注意的点只有几处,

第一处需要注意的是:

在初始化的啥时候,top赋值成0还是-1,所代表的含义是不同的,这里我选择了0,每次压入一个数据,top就要++一次,所以top代表的其实是栈顶下一个位置的下标,所以在获取栈顶元素的时候返回的是arr[top-1]

第二处需要注意的是:

在出栈的时候top是不能一直–的,因为top最多到0,所以专门封装了一个函数StackEmpty来判断栈是否为空。

除了以上两处,也就没有什么特别需要注意的地方了,上面就是顺序栈的实现。

数据结构—队列

队列的概念和结构

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

5

队列实际上比栈还要简单,因为只需要控制一头用来进,一头用来出即可。

队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

7

下面就用代码来实现队列的结果,

// 链式结构:表示队列 
typedef struct QListNode 
{ 
	struct QListNode* pNext; 
	QDataType data; 
}QNode; 
// 队列的结构 
typedef struct Queue 
{ 
	QNode* front; 
	QNode* rear; 
}Queue; 
// 初始化队列 
void QueueInit(Queue* q); 
// 队尾入队列 
void QueuePush(Queue* q, QDataType data); 
// 队头出队列 
void QueuePop(Queue* q); 
// 获取队列头部元素 
QDataType QueueFront(Queue* q); 
// 获取队列队尾元素 
QDataType QueueBack(Queue* q); 
// 获取队列中有效元素个数 
int QueueSize(Queue* q); 
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q); 
// 销毁队列 
void QueueDestroy(Queue* q);

以上是实现队列的接口,

typedef int DateType;
//注意理清楚两个结构体之间的关系
typedef struct QueueNode
{
	struct QueueNode* next;
	DateType data;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	size_t size;
}Queue;
void QueueInit(Queue* ps)
{
	assert(ps);

	ps->head = ps->tail = NULL;
	ps->size = 0;

}
void QueueDestroy(Queue* ps)
{
	assert(ps);

	QNode* cur = ps->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	ps->head = ps->tail = NULL;
	ps->size = 0;

}
void QueuePush(Queue* ps, DateType x)
{
	assert(ps);
	//新的节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("QueuePush fail\n");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	//入队
	if (ps->head == NULL)
	{
		assert(ps->tail == NULL);
		ps->head = ps->tail = newnode;
	}
	else
	{
		ps->tail->next = newnode;
		ps->tail = ps->tail->next;
	}
	ps->size++;
}
void QueuePop(Queue* ps)
{
	assert(ps);
	assert(ps->head);
	//最后一个节点
	if (ps->head->next == NULL)
	{
		free(ps->head);
		ps->head = ps->tail = NULL;
	}
	else
	{
		QNode* newhead = ps->head->next;
		free(ps->head);
		ps->head = newhead;
	}
	ps->size--;
}
DateType QueueFront(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->head->data;
}
DateType QueueBack(Queue* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->tail->data;
}
bool QueueEmpty(Queue* ps)
{
	assert(ps);
	return ps->size == 0;
}
size_t QueueSize(Queue* ps)
{
	assert(ps);
	return ps->size;
}

除此了链式的队列之外,还有一些其他的特殊队列结构,例如环形队列

image-20230413111534070

感兴趣的就自己去扩展了。

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

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

相关文章

v851s g2d 模块 sample 深究

1. g2d 模块概述 g2d 主要功能: 1)旋转:支持90、180、270旋转; 2)镜像反转:H / V; 3) scale:放缩 4)格式转换:yuv 转 rgb 等,多种格式相互间转换; 5)透明叠加功能:实现两个rgb图片叠加; 6)矩形填充,等诸多功能; 2. g2d 配置 1)源码目录:tina-v853-docker/…

Zabbix自定义监控mysql数据库、自动注册服务器及部署代理服务器

目录 一、zabbix自定义监控数据库 1、编写监控脚本 2、服务端测试 3、web页面配置 ①创建自定义监控项 ②创建触发器 ③创建图形 ④测试自定义监控是否成功 二、zabbix自动注册 1、什么是自动注册 2、环境准备 3、 zabbix客户端配置 4、web页面配置自动注册 5、…

Windows系统生产力工具介绍

介绍 本文主要介绍在windows系统上如何安装一些常用的生产力软件,这些软件大多数都是开源免费使用的,包括markdown编辑器、知识管理软件、图片和视频工具、系统工具等,以及程序员专用的开发工具。根据本人的使用经验,将会不定期更…

OpenGL之深入解析屏幕成像和渲染原理

一、CPU 与 GPU CPU 内部组成:GPU 内部组成(ALU:算术逻辑单元,是能实现多组算术运算和逻辑运算的组合逻辑电路):CPU 和 GPU 因为设计之初需求就不一样,所以它们的组成不同,在计算机中的分工也不同。可以看到,GPU 有更多的 ALU,而 CPU 有 Control 单元和 Cache 单元,…

TensorFlow 深度学习第二版:6~10

原文:Deep Learning with TensorFlow Second Edition 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的形象,只…

金融风险计量:数据平滑方法及逆平滑分析

摘要及声明 1:本文从风险分析的角度简单介绍数据平滑方式,重点介绍低频数据的逆平滑分析; 2:本文主要数据通过爬虫获取; 3:模型实现基于python3.8; 处理金融数据时我们经常会遇到有噪音的数…

规模化敏捷框架:Spotify

Spotify 是全球最大、最受欢迎的流媒体音乐服务平台,预估用户总量已达2.86亿。Spotify 取得成功的一个关键因素就在于公司采用了一个独特方法: 围绕工作任务进行组织构建以提高团队敏捷性。Spotify 工程团队把提高团队敏捷性的经验记录了下来,并把经验分…

Java web学习记录(二)数据库的使用

学习Java web的前置条件就是数据库,只有学了数据库才能更好的处理网站应用产生的数据。 初识数据库 数据库(Database)顾名思义就是一个存储数据的仓库,通过它就可以直接查找到你想要的数据,举个简单的例子&#xff0…

IPSEC实验(IPSECVPN点到点,DSVPN,IPSECVPN旁挂)

目录一、复现实验1、防火墙的IPSECVPN点到点实验-1,拓扑图的搭建-2,配置IP,开通ping,并且设置策略-3,在网络中的IPSEC进行配置第一阶段:发出的UDP500流量第二阶段 发出的ESP流量二台防火墙建立策略禁用其它策略,在IPSEC上配置策略…

系统应满足的性能指标计算及系统性能衡量

根据运营数据计算系统应该满足的性能指标 计算正常业务操作(稳定性测试)的并发量 计算峰值业务操作(压力测试)的并发量 如何进行并发数计算(稳定性测试和压力测试) 使用阶梯线程组自定义模拟用户数量。 …

前端开发工具-Visual Studio Code-插件下载-迁移到新电脑

背景 前端使用的开发工具一般是Visual Studio Code,很多辅助功能,比如字体高亮、单词拼写检查、预览图片等需要安装插件。但是插件在原来的电脑,不想下载或者自己是新人,想迁移同事的插件,或者新电脑没有外网。 以下…

手把手教学在windows系统上将pytorch模型转为onnx,再转为ncnn的全过程

前言 最近呢,在忙一个项目,需要将pytorch训练的模型部署在移动端。然后遇到也遇到了一些坑,简单的记录一下整个过程,转换的模型就使用经典的分类网络模型mobilenet_v2。 将pytorch模型转换为onnx模型 环境准备 这个步骤比较简…

U+平台和华为软开平台怎么拉取远程项目作为新项目

这是根据聊天记录改的帖子,这样应该算得上是一篇技术博客了吧,又完成一个指标【狗头】 用idea作为开发工具 首先连接校园网,然后进入U网址http://10.5.1.21:30080/student/group 从这进去 修改https密码,选择修改,不…

Ubuntu20.04 安装QGIS

qgis的git: GitHub - qgis/QGIS: QGIS is a free, open source, cross platform (lin/win/mac) geographical information system (GIS) qgis的官网:Welcome to the QGIS project! qgis插件包下载地址:https://plugins.qgis.org/plugins/ 1.Prerequisi…

前 K 个高频元素(力扣刷题代码随想录刷题)

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 思路: 要统计元素出现频率对频率排序找出前K个高频元素首先统计元素出现的频率,这一类的问题可以使用map来进行统计。 然后是对频率…

商汤科技推出“日日新SenseNova”,大模型体系赋能人工智能新未来

2023年4月10日,商汤科技SenseTime技术交流日活动在上海举行,分享了以“大模型大算力”推进AGI(通用人工智能)发展的战略布局,并公布了商汤在该战略下的“日日新SenseNova”大模型体系。 公开信息显示,商汤科…

使用Python突破某网游游戏JS加密限制,进行逆向解密,实现自动登录

兄弟们天天看基础看腻了吧 今天来分享一下如何使用Python突破某网游游戏JS加密限制,进行逆向解密,实现自动登录。 逆向目标 目标:某 7 网游登录主页:aHR0cHM6Ly93d3cuMzcuY29tLw接口:aHR0cHM6Ly9teS4zNy5jb20vYXBpL…

面试了上百位性能测试后,我发现了一个令人不安的事实...

在企业中负责技术招聘的同学,肯定都有一个苦恼,那就是招一个合适的测试太难了!若要问起招哪种类型的测试最难时,相信很多人都会说出“性能测试”这个答案。 每当发布一个性能测试岗位,不一会就能收到上百份简历&#…

商会协会入会资源需求活动小程序开发

商会协会入会资源需求活动小程序开发 功能列表: 用户注册:用户可以通过小程序注册账号并加入商会协会。会员管理:可以管理会员的基本信息,包括个人信息、公司信息、会员资格等级等。同时,管理者可以根据会员等级制定…

JavaSE抽象类和接口

文章目录JavaSE抽象类和接口一、抽象类1、抽象类概念2、抽象类特性二、接口1、接口概念2、接口特性3、多接口4、接口之间的继承5、常用接口使用6、抽象类和接口的区别三、Object类JavaSE抽象类和接口 一、抽象类 1、抽象类概念 一个类中没有包含足够的信息来描绘一个具体的对…