数据结构之栈

🎉welcome🎉
✒️博主介绍:博主大一智能制造在读,热爱C/C++,会不定期更新系统、语法、算法、硬件的相关博客,浅浅期待下一次更新吧!
✈️算法专栏:算法与数据结构
😘博客制作不易,👍点赞+⭐收藏+➕关注

概念

在生活中,手枪的弹夹子弹是从最上面一颗一颗出去的,而子弹装进弹夹里面的时候,子弹的顺序和子弹出去的顺序正好是相反的,即子弹是先进后出的, 在数据结构当中,同样有一种结构是先进后出,它就是栈。栈是一种特殊的线性表,它只限定在表尾进行插入和删除,并且只能访问到表尾的数据,表尾可以被访问到的元素被叫做栈顶,插入数据的时候叫做入栈,删除数据的时候叫出栈,元素在栈中时叫做压栈。栈这种先进后出(Last In First Out)的线性表结构,简称LIFO结构

顺序栈

栈是特殊的线性表,在实现栈的时候,可以使用顺序表实现顺序栈,也可以使用链表变成链栈,而对于顺序栈,栈顶和栈底如何选择?对于顺序栈而言,栈顶如果选在首元素位置即下标0位置,则会导致在入栈和出栈的时候进行大量的挪动数据,时间复杂度在O(N),而当栈底选在首元素位置,栈顶位置放在尾元素位置的时候,只需要记录下尾部下标,就可以在**O(1)**时间进行入栈和出栈。

顺序栈的结构体成员

对于顺序栈而言,选择了尾部作为栈顶,那结构体中就需要一个成员来记录栈顶元素下标发下一个位置即栈内元素个数,同时,对于采用动态内存的栈,使栈没有存储上限,这是还需要个变量来记录容量,这个容量表示栈最多可以放多少元素,当栈顶和容量相当时就会进行扩容。

typedef int StDataType;typedef struct stack
{StDataType* data;		//数据存放int top;				//栈顶下标 or 栈内元素个数int capacity;			//栈容量
};

顺序栈的初始化

对于需要动态内存扩容的顺序栈而言,初始化是开空间外加更改容量和栈顶下标。

void StInit(St* st)
{assert(st);st->data = (StDataType*)malloc(sizeof(StDataType) * 4);if (st->data == NULL){perror("malloc");}st->top = 0;st->capacity = 4;
}

顺序栈的销毁

与初始化相对的就是栈的销毁,对于顺序栈而言,因为底层空间为连续空间,则释放空间时直接一次就可以释放完成,而top和capacity只需要置0。

void StDestroy(St* st)
{assert(st);free(st->data);st->data = NULL;st->top = 0;st->capacity = 0;
}

顺序栈的入栈

顺序栈的栈顶是顺序表的表尾,因为已经记录下栈尾下一个元素的位置,所以入栈可以直接入,不需要去找尾,当元素入栈后,将top更新即可,注意:在进行入栈操作之前,需要先进行判断,判断是否还有位置,如果没有,就需要进行扩容。

//扩容
void Stdilata(St* st)
{assert(st);//断言如果为空则说明传过来的数据有问题if (st->top == st->capacity)//当我们存放的元素个数和容器最大容量一样的时候,说明需要扩容{StDataType* tmp = (StDataType*)realloc(st->data, sizeof(StDataType) * st->capacity * 2);if (tmp == NULL){perror("");return;}st->data = tmp;//因为realloc开辟的空间的时候可能换到另一个地方st->capacity *= 2;}
}//入栈
void StPush(St* st, StDataType x)
{assert(st);Stdilata(st); //扩容函数内部自己检查是否容量已满st->data[st->top++] = x;//后置++是先使用在++,当插入元素后top才会更新
}

顺序栈的判空

对于顺序栈而言,判空只需要判断top即可,top为0的时候为空,返回真。

bool StEmpty(St* st)
{assert(st);return st->top == 0;
}

顺序栈的出栈

出栈时候必须要删除元素吗?并不一定,这个元素出栈,只要无法访问到这个元素即可,那这里可以直接让top进行减减,对于栈而言,访问元素只能访问到top-1,而这时top–,那就访问不到在top–top-1的位置,即原栈顶位置,那原栈顶也属于出栈。

void Stpop(St* st)
{assert(!StEmpty(st));//判空函数内部判断stst->top--;
}

顺序栈内的元素个数

顺序栈内的元素个数已经用top记录下来,直接返回top

int StSize(St* st)
{assert(st);return st->top;
}

顺序栈获取栈顶元素

同样已经用top记录下尾部下一个位置,直接返回数组元素第top-1个即可。

StDataType StTop(St* st)
{assert(st);return st->data[st->top - 1];
}

链式栈

对于链式栈而言,是选择单链表还是其他链表?对于栈而言,只需要操作栈顶元素即可,而单链表对于头删和头插是可以做到O(1)的,所有对于链式栈而言,采用单链表做栈是较为合适的,其他的链表用在栈上有点大材小用了,单链表做栈,拿头部当栈顶,这一点和顺序表是不一样的,同时,对于链表而言,结构体成员当中就可以不用capacity来记录容量的大小,而top是否还需要?从顺序栈的各类函数来看,top是很有必要的,但是top的作用其实用size来表示是更加合适的,而链式栈和顺序栈的相关函数内部实现和思路是一样的,只是将顺序表换成了链表,入栈和出栈分别对应链表的头插和头删,栈顶元素就是头节点保存的data。

栈的应用

递归

函数的递归就是使用了栈,每个使用函数的时候,这个函数就会入栈,这里的栈指的是系统中的栈区,而函数入栈之后,在运行内部又调用了这个函数,此时这次调用还没有结束,新的调用又压到了这个函数上面,系统就会执行这次新的调用,直到在无新的调用,最上面压栈的函数调用完毕出栈,露出下面的,在接着执行,直到调用完最下面即第一次调用的这个函数,完成递归。

递归的好处

递归写起来很简便,对于递归而言,往往可以将一长串的代码变成几行,递归用的好,往往可以增加代码的可读性,使自己的代码更加通俗易懂。

递归需要注意的地方

当要使用递归的时候,一定要注意有条件可以让这个函数停下来,否则就会出现栈溢出,何为栈溢出栈溢出指的是当前调用的东西已经将系统的栈填满了,但是这个时候还在往栈区进行入栈的操作,这里就会有人出现疑问,上面实现的栈是可以进行动态内存申请的,系统的栈难道是静态栈吗?确切的说,不完全是,系统的栈是会随着入栈出栈随机改变的,而对于一些编译器,如:VS、VScode、clion、devc++,它们往往会给栈一个容量的限制,超出这个容量就会造成栈溢出,所以递归一定需要有条件停下来才可以。

递归经典应用——斐波那契数列

斐波那契数列又叫黄金分割数列,同时也叫兔子数列, 斐波那契数列起源于斐波那契提出的一个问题:“如果一个兔子在出生两个月的时候就拥有的生育能力,一对兔子可以在一个月生一对小兔子,假设所有兔子都不会死,一年之后有多少兔子?”当将每个月的数据列出来的时候,就会发现前面两项之和就等于下一项,这也是斐波那契数列的定义,前两项之和等于下一项,那这个和递归有什么关系呢?对比一下采用循环迭代写出的代码和递归写出的代码。

int Fib1(int sum)
{if (sum < 2) return sum == 0 ? 0 : 1;int x = 1;int y = 1;int z = 0;for (int i = 3; i <= sum; i++){z = x + y;x = y;y = z;}return z;
}int Fib2(int sum)
{if (sum < 2) return sum == 0 ? 0 : 1;//当是0的时候返回0return Fib2(sum - 1) + Fib2(sum - 2);
}

可以看到下面采用递归的代码对比迭代看起来很简洁,代码少了很多,但是这里的运行效率却是迭代快,所以递归并不完全优于迭代,要看情况决定。

四则运算求表达式

计算机在处理四则运算时就运用到了栈,具体如何处理可以看我这篇博客:计算机是如何计算四则运算表达式的?

🚀专栏:算法与数据结构
🙉都看到这里了,留下你们的👍点赞+⭐收藏+📋评论吧🙉

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

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

相关文章

Python建造者模式介绍、使用方法

一、Python建造者模式简介 1. 概念 建造者模式(Builder Pattern)是一种创建型设计模式&#xff0c;它可以将复杂对象的构造与表示分离&#xff0c;使得同样的构建过程可以创建不同的表现形式。该模式通过一步一步创建复杂对象&#xff0c;将对象的构造过程与表示过程解耦。 2.…

web前端tips:js继承——原型链继承

原型链继承 原型链继承是 JavaScript 中实现继承的一种方式&#xff0c;它通过使用原型来实现对象之间的继承关系。 在 JavaScript 中&#xff0c;每个对象都有一个原型&#xff08;prototype&#xff09;&#xff0c;它是一个指向另一个对象的引用。当我们访问一个对象的属性…

什么是算法

算法的概念 算法&#xff08;algorithm&#xff09;是解决一系列问题的清晰指令&#xff0c;也就是&#xff0c;能对一定规范的输入&#xff0c;在有限的时间内获得所要求的输出。 简单来说&#xff0c;算法就是解决一个问题的具体方法和步骤。算法是程序的灵魂 一、算法的特征…

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”

科技云报道原创。 没有人能预见未来&#xff0c;但我们可以因循常识&#xff0c;去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底&#xff0c;由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场&#xff0c;生成式AI成为科技市场热点&#xff0c…

ES6:Object.assign方法详解

ES6&#xff1a;Object.assign方法详解 1、前言2、语法3、基本用法3.1 目标对象和源对象无重名属性3.2 目标对象和源对象有重名属性3.3 有多个源对象3.4 其他情况3.4.1 只有一个参数时&#xff0c;Object.assign会直接返回该参数3.4.2 如果该参数不是对象&#xff0c;则会先转成…

每日一道面试题之介绍一下Iterator

Iterator是Java中的一个接口&#xff0c;用于遍历集合&#xff08;Collection&#xff09;中的元素。通过Iterator&#xff0c;可以按顺序访问集合中的每个元素&#xff0c;而无需了解集合的内部实现细节。 使用Iterator的一般步骤如下&#xff1a; 通过调用集合的iterator()…

SOC FPGA之HPS模型设计(二)

根据SOC FPGA之HPS模型设计(一)&#xff0c; Quartus工程经过全编译后会产生Handoff文件夹、SOPCINFO文件、SVD文件 二、生成Preloader镜像文件 通过信息交换文件Handoff文件生成Preloader&#xff0c;需要用到SOC EDS Preloader也被称为spl(Second Program Loader)或u-boot…

【云原生 • Kubernetes】认识 k8s、k8s 架构、核心概念点介绍

目录 一、Kubernetes 简介 二、Kubernetes 架构 三、Kunbernetes 有哪些核心概念&#xff1f; 1. 集群 Cluster 2. 容器 Container 3. POD 4. 副本集 ReplicaSet 5. 服务 service 6. 发布 Deployment 7. ConfigMap/Secret 8. DaemonSet 9. 核心概念总结 一、Kubern…

基于Ko-time的Springboot单体化调用链追踪实践

目录 前言 一、关于Ko-Time 1、是什么&#xff1f; 2、ko-time更新时间线 二、Ko-time怎么用&#xff1f; 1、依赖引入 2、配置集成 3、权限放行 三、链路追踪 1、系统运行 2、链路追踪 3、长时间调用模拟 总结 前言 熟悉微服务的老司机一定了解&#xff0c;在微服务模…

Web端即时通讯技术(SEE,webSocket)

目录 背景简介个人见解被动推送轮询简介实现 长轮询&#xff08;comet&#xff09;简介实现 比较 主动推送长连接&#xff08;SSE&#xff09;简介实现GETPOST 效果 webSocket简介WebSocket的工作原理:WebSocket的主要优点:WebSocket的主要缺点: 实现用法一用法二 **效果** 比较…

学习笔记|大模型优质Prompt开发与应用课(二)|第四节:大模型帮你写代码,小白也能做程序

文章目录 01软件开发产业趋势与技术革新软件开发产业趋势与技术革新技术性人才很受欢迎软件开发产业趋势与技术革新技术门槛越来越低 02 大模型驱动的软件开发需求分析prompt 产品设计开发和测试prompt输出回复promptpromptprompt回复 发布和部署promptprompt 维护和更新prompt…

Docker中的网络

文章目录 网络网桥&#xff08;bridge&#xff09;创建网桥接口hostnonecontaineroverlayoverlay底层原理 网络 网桥&#xff08;bridge&#xff09; 在Docker中&#xff0c;网桥&#xff08;Bridge&#xff09;是一种网络驱动&#xff0c;用于实现Docker容器之间和容器与宿主…

SpringBoot中接口幂等性实现方案-自定义注解+Redis+拦截器实现防止订单重复提交

场景 SpringBootRedis自定义注解实现接口防刷(限制不同接口单位时间内最大请求次数)&#xff1a; SpringBootRedis自定义注解实现接口防刷(限制不同接口单位时间内最大请求次数)_redis防刷_霸道流氓气质的博客-CSDN博客 以下接口幂等性的实现方式与上面博客类似&#xff0c;…

MySQL - 记一次 HikariDataSource + Etcd 组合技打爆数据库连接数

问题描述 如题所述&#xff0c;我们每新增一个数据源并且往 etcd 去生产的时候&#xff0c;etcd 消费者收到监听到的内容去消费&#xff0c;产生大量的数据库连接&#xff08;通过 SHOW PROCESSLIST 查到&#xff09; 原因分析 故事是因为项目本身有一个多租户功能&#xff0…

剑指YOLOv7改进最新MPDIoU损失函数(23年7月首发论文):论文实测YOLOv7模型涨点,超越现有多种G/D/C/EIoU,高效准确的边界框回归的损失

💡本篇内容:剑指YOLOv7改进最新MPDIoU损失函数(23年7月首发论文):论文实测YOLOv7模型涨点,超越现有多种G/D/C/EIoU,高效准确的边界框回归的损失 💡🚀🚀🚀本博客 改进源代码改进 适用于 YOLOv7 按步骤操作运行改进后的代码即可 💡:重点:该专栏《剑指YOLOv7原…

python pygbag教程 —— 在网页上运行pygame程序(全网中文教程首发)

pygame是一款流行的游戏制作模块&#xff0c;经过特殊的方式编译后&#xff0c;可以在浏览器web网页上运行。web上的打包主要使用第三方模块pygbag。 pygame教程&#xff1a;Python pygame(GUI编程)模块最完整教程&#xff08;1&#xff09;_pygame模块详解_Python-ZZY的博客-…

【配置环境】Windows下 VS Code 远程连接虚拟机Ubuntu

一&#xff0c;环境 Windows 11 家庭中文版VMware Workstation 16 Pro &#xff08;版本&#xff1a;16.1.2 build-17966106&#xff09;ubuntu-22.04.2-desktop-amd64 二&#xff0c;关键步骤 Windows下安装OpenSSHVS Code安装Remote - SSH插件 三&#xff0c;详细步骤 在Ubun…

kotlin获取泛型集合的类型信息

通过 reified 关键字和内联函数来实现 inline fun <reified T> getClassFromList(list: List<T>): Class<T> {return T::class.java }fun main() {val list listOf("Hello", "World")val clazz getClassFromList(list)println(clazz)…

React 前端应用中快速实践 OpenTelemetry 云原生可观测性(SigNoz/K8S)

OpenTelemetry 可用于跟踪 React 应用程序的性能问题和错误。您可以跟踪从前端 web 应用程序到下游服务的用户请求。OpenTelemetry 是云原生计算基金会(CNCF)下的一个开源项目&#xff0c;旨在标准化遥测数据的生成和收集。已成为下一代可观测平台的事实标准。 React(也称为 Re…

【K8s】k8s配置存储卷PersistentVolumeClaim里的readwriteonce是什么意思

示例 参考这个示例 对于其中的ReadWriteOnce参数 ReadWriteOnce是Kubernetes PersistentVolume的访问模式之一。具体来说&#xff1a; ReadWriteOnce&#xff1a;卷可以被一个节点以读写模式挂载。ReadOnlyMany&#xff1a;卷可以被多个节点以只读模式挂载。ReadWriteMany&…