【数据结构】【版本1.3】【线性时代】——栈



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、栈的概念
  • 二、栈的模拟实现
    • 2.1 定义
    • 2.2 初始化
    • 2.3 销毁
    • 2.4 压栈
    • 2.5 判空
    • 2.6 出栈
    • 2.7 获取栈顶元素
    • 2.8 获取栈的元素个数
    • 2.9 元素访问
  • 三、栈的应用场景

引言

数据结构世界——栈(Stack)

一、栈的概念

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈:栈的删除操作叫做出栈。出数据也在栈顶

二、栈的模拟实现

栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。

2.1 定义

typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
  • 当前元素个数用栈顶top来表示,是栈独有的表示方法

2.2 初始化

void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->top = 0;//top指向栈顶元素的下一个位置pst->capacity = 0;
}
  • 栈的初始化,top可以为0或-1,top为0,则指向栈顶元素的下一个位置,top为-1,则指向栈顶元素的位置
  • 这里选用top为0,因为后面写的适合方便理解

2.3 销毁

void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->top = pst->capacity = 0;
}
  • 栈的销毁和顺序表一样,直接释放数组空间,将top和capacity置为0

2.4 压栈

void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->top == pst->capacity){int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail");return;}pst->a = tmp;pst->capacity = newCapacity;}pst->a[pst->top++] = x;
}
  • 先判断是否需要扩容,因为这里只有压栈函数需要判断扩容,所以就不用专门再写一个扩容函数
  • 初始容量为4,后续每次进行2倍扩容(这样扩容比较合理,不会太频繁,也不会太浪费)
  • 再将元素压栈,top++

ps:realloc函数在pst为NULL时,充当malloc的作用,所以既可以为初始栈开辟空间,又可以扩容 。

2.5 判空

bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}
  • 如果top为0,则栈为空,返回真;反之,返回假

2.6 出栈

void STPop(ST* pst)
{assert(pst);assert(!STEmpty(pst));pst->top--;
}
  • assert断言判断,栈是否为空,因为top不能减到负数
  • 再将top- -,掩盖栈顶元素

2.7 获取栈顶元素

STDataType STTop(ST* pst)
{assert(pst);assert(!STEmpty(pst));return pst->a[pst->top - 1];
}
  • assert断言判断,栈是否为空,因为top不能减到负数
  • 再返回栈顶元素,因为这里top指向的是栈顶元素的下一位,所以下标访问时top要减1

2.8 获取栈的元素个数

int STSize(ST* pst)
{assert(pst);return pst->top;
}
  • top指向的是栈顶元素的下一位,所以数值上就是栈的元素个数

这里很多函数实现都很简单,有些操作直接外部对结构体都可以直接实现,但最后还是写成函数封装,因为top的含义有多重,防止别人使用时误解,导致使用错误 。

2.9 元素访问

栈中元素访问(打印),不是用函数实现。因为它的特殊结构,决定了它的元素不能从任意位置访问 ,必须符合后进先出原则才可以。

void TestStack1()
{ST st;//初始化STInit(&st);//压栈STPush(&st, 1);STPush(&st, 2);printf("%d\n", STTop(&st));STPop(&st);STPush(&st, 3);STPush(&st, 4);STPush(&st, 5);//打印while (!STEmpty(&st)){printf("%d\n", STTop(&st));STPop(&st);}//销毁STDestroy(&st);
}
  • 通常用循环的方式进行访问,同时每访问一个元素,就将它弹出栈,在进行下一个元素的访问

三、栈的应用场景

  1. 函数调用与返回
    在程序执行过程中,函数调用和返回是栈结构的一个典型应用。当函数被调用时,其返回地址、局部变量等信息被压入调用栈中;当函数返回时,这些信息从调用栈中弹出并恢复程序的执行状态。

  2. 浏览器的前进后退
    在浏览器中浏览网页时,我们使用的前进和后退功能也是栈结构的一个应用。浏览器将用户访问过的网页地址保存在一个栈中,当用户点击后退按钮时,浏览器从栈顶弹出最近访问的网页地址并跳转到该网页;当用户点击前进按钮时,浏览器将之前弹出的网页地址重新压入栈中并跳转到该网页。

  3. 表达式求值
    在编译器和解释器中,表达式求值也是栈结构的一个重要应用。编译器和解释器将表达式转换为逆波兰表示法(Reverse Polish Notation, RPN),并使用栈来存储和操作操作数和操作符,从而实现表达式的求值。


真诚点赞,手有余香

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

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

相关文章

RAG优化技巧|7大挑战与解決方式|提高你的LLM能力

在当今快速发展的人工智能领域,大型语言模型(LLM)已经成为无处不在的技术,它们不仅改变了我们与机器交流的方式,还在各行各业中发挥着革命性的影响。 然而,尽管LLM RAG的能力已经让人惊叹,但我…

浅谈配置元件之JDBC连接配置

浅谈配置元件之JDBC连接配置 通过使用“JDBC连接配置”配置元件(JDBC Connection Configuration),您可以轻松地在JMeter测试计划中集成数据库交互能力。本指南将详细介绍如何设置和使用此配置元件来连接数据库并执行SQL查询。 1. 准备工作 …

深度学习500问——Chapter12:网络搭建及训练(1)

文章目录 12.1 TensorFlow 12.1.1 TensorFlow 是什么 12.1.2 TensorFlow的设计理念是什么 12.1.3 TensorFlow特点有哪些 12.1.4 TensorFlow的系统架构是怎样的 12.1.5 TensorFlow编程模型是怎样的 12.1.6 如何基于TensorFlow搭建VGG16 12.1 TensorFlow 12.1.1 TensorFlow 是什…

微服务架构:解构现代应用程序的未来

目录 前言1. 微服务架构的基本概念1.1 什么是微服务架构1.2 微服务与单体架构的对比 2. 微服务架构的优势2.1 灵活性与可扩展性2.2 持续交付与部署2.3 技术多样性2.4 故障隔离 3. 微服务架构的挑战3.1 服务间通信和数据一致性3.2 运维复杂度3.3 安全性3.4 开发团队的协作 4. 微…

内核学习——1、list_head

双向循环链表:list_head 头节点head是不使用的: struct list_head { struct list_head *next, *prev; }; 结构体中没有数据域,所以一般把list_head嵌入到其他结构中使用 struct file_node { char c; struct list_head node; }; 此时&#xff…

手机铃声下载2个必备技巧,定制化铃声,彰显个性魅力

手机铃声,就像是独特的信号灯,不仅仅是通知我们来电或信息的方式,更是展现个人品位和魅力的武器。手机铃声下载和定制,让你的手机从千万舰队中脱颖而出。在接下来的文章中,我们将详细探讨铃声下载技巧的具体操作步骤&a…

介绍.NET 6款好看的winform开源UI库

开篇概述 在软件开发的世界里,用户界面(UI)是连接用户与程序的桥梁。对于使用.NET Framework进行WinForms应用程序开发的开发者来说,拥有一个美观、直观且功能丰富的UI库无疑是提升用户体验的关键。今天,我们将一起探索…

2024人工智能指数报告(二):技术性能

背景 从2017年开始,斯坦福大学人工智能研究所(HAI)每年都会发布一份人工智能的研究报告,人工智能指数报告(AII),对上一年人工智能相关的数据进行跟踪、整理、提炼并进行可视化。这份指数报告被认…

深度学习1 -- 开头

一 前言 感觉用这玩意越来越多,所以想学学。不过没想好怎么学,也没有提纲,买了两本书,一本是深度学习入门,小日子写的。还有一本就是花书。还有就是回Gatech参加线上课程,CS7643。 CS 7643: Deep Learnin…

【stm32-新建工程-寄存器版本】

stm32-新建工程-寄存器版本 ■ 下载相关STM32Cube官方固件包(F1,F4,F7,H7)■ 1. ST官方搜索STM32Cube■ 2. 搜索 STM32Cube■ 3. 点击获取软件■ 4. 选择对应的版本下载■ 5. 输入账号信息■ 6. 出现下载弹框&#xff…

怎么开启22端口访问权限,让别的机器通过ssh或者向日葵等远程控制工具链接

在Ubuntu 24.04上开启22端口访问权限,并允许其他机器通过SSH或向日葵等远程控制工具进行连接,您需要进行以下几步操作: 1. 安装并配置SSH服务器 安装OpenSSH服务器: sudo apt update sudo apt install openssh-server检查SSH服务状态: sudo …

推荐 2 个 牛哔哄哄 的 GitHub 项目

推荐两个开源的 GitHub 项目,一个基于大模型的企业级知识库问答系统,支持管理企业知识库、对话问答、RAG 等功能。 另外一个是计算机视觉的工具箱,使用它你可以在你电脑上实现人体跟踪、分割、检测等一系列计算机视觉的场景。 01 基于 LLM 大…

CR、 LF、CRLF的区别

一、CR LF CRLF的区别 CR (Carriage Return),LF (Line Feed),以及 CRLF (Carriage Return Line Feed) 是用于表示文本中换行的控制字符,它们在不同的操作系统和环境中有着不同的使用习惯: CR (Carriage Return) 含义&#xff1…

【unity笔记】二、海洋系统Crest Ocean System插件使用

一、介绍 Crest 是 Unity 技术先进的海洋系统。 它专为性能而设计,并大量使用细节级别 (LOD) 策略和 GPU 加速来实现快速更新和渲染。它还具有高度的灵活性,允许对水形状/泡沫/动态波浪/等进行任何自定义输入,并具有直…

奇迹MU服务器租用一个月需要多少钱?

在网络游戏产业迅猛发展的今天,越来越多的人参与到各种各样的网络游戏当中。其中,《奇迹MU》作为一款经典的多人在线角色扮演游戏,吸引了大量玩家的关注与热爱。为了保证游戏的流畅运行和玩家体验,租用高性能的服务器至关重要。 《…

01 基础入门 编写你的第一个 Go 语言程序

从这节课开始,我会带你走进 Go 语言的世界。我会用通俗易懂的语言,介绍 Go 语言的各个知识点,让你可以从零开始逐步学习,再深入它的世界。不管你以前是否接触过 Go 语言,都可以从这个专栏中受益。 现在,让…

时隔一年,SSD大涨价?

同样产品,2T,去年400多到手,今年700。 去年 今年

【机器学习】MSE和MAE损失函数有什么区别?回归问题的常用损失函数

在机器学习和统计学中,均方误差(Mean Squared Error, MSE)和平均绝对误差(Mean Absolute Error, MAE)是两种常用的损失函数,用于评估模型预测值与真实值之间的差异。它们的区别主要体现在对误差的处理方式和…

使用 Netty 自定义解码器处理粘包和拆包问题详解

使用 Netty 自定义解码器处理粘包和拆包问题详解 在网络编程中,粘包和拆包问题是常见的挑战。粘包是指多个数据包在传输过程中粘在一起,而拆包是指一个数据包在传输过程中被拆分成多个部分。Netty 是一个高性能、事件驱动的网络应用框架,提供…

从零开始精通Onvif之录像存储

💡 如果想阅读最新的文章,或者有技术问题需要交流和沟通,可搜索并关注微信公众号“希望睿智”。 概述 Onvif的录像存储功能主要由Media、Recording和Replay三个关键服务共同支持。它们协同工作,为录像的存储、检索和播放提供了标准…