当前位置: 首页 > news >正文

一文了解栈

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、栈是什么?
  • 二、栈的实现思路
    • 1.顺序表实现
    • 2.单链表实现
    • 3.双向链表实现
  • 三、接口函数的实现
    • 1.栈的定义
    • 2.栈的初始化
    • 3.栈的销毁
    • 4.入栈
    • 5.出栈
    • 6.返回栈顶元素
    • 7.判空
    • 8.返回栈中数据个数
  • 四、文件总览
    • 1.头文件
    • 2.功能函数
    • 3.测试文件
  • 总结


在这里插入图片描述

前言

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


一、栈是什么?

堆栈又名栈(stack),它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
在这里插入图片描述
在这里插入图片描述

二、栈的实现思路

1.顺序表实现

代码如下(示例):

typedef struct StackList
{STDataType* a; //指向动态开辟的空间int top; //栈顶所在下标的下一位(也可以指向栈顶)int capacity;//栈容量
}ST;

在这里插入图片描述

2.单链表实现

代码如下(示例):

typedef struct StackNode
{STDataType x;//数据StackNode* next;//指针域,指向下一结点
}ST;
struct Stack
{ST* phead;//指向第一个结点ST* ptail;//指向尾结点
}

在这里插入图片描述

3.双向链表实现

typedef struct StackNode
{STDataType x;//数据StackNode* next;//指向下一结点StackNode* prev;//指向上一结点
}ST;
struct Stack
{ST* phead;//指向第一个结点ST* ptail;//指向尾结点
}

在这里插入图片描述
在这里我们推荐采用顺序表来实现对栈的操作,原因如下:

  1. 栈的特性利用了顺序表尾插尾删效率高的特性,虽然有时需要扩容,但是链表创建结点也同样需要成本,而顺序表扩容频率不像链表一样如此频繁。链表频繁开辟节点也是很耗时的。
  2. 我们知道CPU与主存速度上存在巨大差距,为了提高效率,CPU和主存之间还存在着高速缓存。 CPU访问缓存的速度是快于主存。每次CPU取数据时会访问缓存看看存不存在所需的数据,如果不存在才会访问主存,然后将数据所在的内存块加载到缓存中。由于顺序表空间是连续的,根据缓存的空间局部性原理,采用顺序表命中率会高于链表,所以效率高。

三、接口函数的实现

1.栈的定义

typedef int STDataType;
typedef struct Stack 
{STDataType* a;//动态开辟内存int top;//栈顶的下一位int capacity;栈的容量
}ST;

这里top定义为栈顶下一位是为了下面下表访问方便,也可以定义为指向栈顶的top可以根据个人需要决定。

2.栈的初始化

void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->capacity = 0;pst->top = 0;
}

初始化时,空间a先置空指针,capacity和top置零,这是栈没有数据,top指向0,也确实是栈顶的下一位。

3.栈的销毁

void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->capacity = pst->top = 0;
}

先对pst进行assert断言,再对开辟的空间进行释放,将指针置零,capacity和top置零即可。

4.入栈

void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top){int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;STDataType*tmp=(STDataType*)realloc(pst->a, newcapacity*sizeof(STDataType));if (tmp == NULL){perror("realloc");return;}pst->a = tmp;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}

入栈需要注意的点是判断是否容量够用,当capacity和top相等时存满,需要扩充。在扩充时需要判断原容量是不是0,这里进行一个三目操作符判断。之后就是realloc扩容,最后将相应的capacity和top修改就行。

5.出栈

void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}

出栈时应判断栈是否为空,所以这里除了判断pst的有效性,还要判断top的位置。最后让top向前移一位就进行了出栈。

6.返回栈顶元素

STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top-1];
}

判断pst有效性和栈是否为空,再将栈顶的元素返回即可。

7.判空

bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}

这里需要返回bool类型,需要加<stdbool.h>头文件。当top为零时栈为空,返回true,否则返回false。

8.返回栈中数据个数

int STSize(ST* pst)
{assert(pst);return pst->top;
}

这里因为我们的top指向栈顶数据的下一位,所以top即为数据个数。返回即可。

四、文件总览

1.头文件

#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
#include<stdlib.h>typedef int STDataType;
typedef struct Stack 
{STDataType* a;int top;int capacity;
}ST;// 初始化和销毁
void STInit(ST* pst);
void STDestroy(ST* pst);// 入栈  出栈
void STPush(ST* pst, STDataType x);
void STPop(ST* pst);// 取栈顶数据
STDataType STTop(ST* pst);// 判空
bool STEmpty(ST* pst);
// 获取数据个数
int STSize(ST* pst);

2.功能函数

#include"Stack.h"void STInit(ST* pst)
{assert(pst);pst->a = NULL;pst->capacity = 0;pst->top = 0;
}void STDestroy(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->capacity = pst->top = 0;
}void STPush(ST* pst, STDataType x)
{assert(pst);if (pst->capacity == pst->top){int newcapacity = pst->capacity == 0 ? 4 : 2 * pst->capacity;STDataType*tmp=(STDataType*)realloc(pst->a, newcapacity*sizeof(STDataType));if (tmp == NULL){perror("realloc");return;}pst->a = tmp;pst->capacity = newcapacity;}pst->a[pst->top] = x;pst->top++;
}void STPop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}STDataType STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top-1];
}bool STEmpty(ST* pst)
{assert(pst);return pst->top == 0;
}int STSize(ST* pst)
{assert(pst);return pst->top;
}

3.测试文件

int main()
{// 入栈:1 2 3 4// 出栈:4 3 2 1  /  2 4 3 1ST s;STInit(&s);STPush(&s, 1);STPush(&s, 2);printf("%d ", STTop(&s));STPop(&s);STPush(&s, 3);STPush(&s, 4);while (!STEmpty(&s)){printf("%d ", STTop(&s));STPop(&s);}STDestroy(&s);
}

在这里插入图片描述


总结

这就是本期文章的全部内容,期待你的一键三连和评论。

相关文章:

一文了解栈

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、栈是什么&#xff1f;二、栈的实现思路1.顺序表实现2.单链表实现3.双向链表实现 三、接口函数的实现1.栈的定义2.栈的初始化3.栈的销毁4.入栈5.出栈6.返回栈…...

C语言----汉诺塔问题

1.什么是汉诺塔问题 简单来说&#xff0c;就是有三个柱子&#xff0c;分别为A柱&#xff0c;B柱&#xff0c;C柱。其中A柱从上往下存放着从小到大的圆盘&#xff0c;我们需要借助B柱和C柱&#xff0c;将A柱上的所有圆盘转移到C柱上&#xff0c;并且一次只能移动一个圆盘&#…...

Python中驼峰命名法和下划线命名法相互转换的实战代码

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

【hackmyvm】vivifytech靶机

渗透思路 信息收集端口扫描端口服务信息目录扫描爆破hydra--sshgit提权 信息收集 ┌──(kali㉿kali)-[~] └─$ fping -ag 192.168.9.0/24 2>/dev/null 192.168.9.119 --主机 192.168.9.164 --靶机个人习惯&#xff0c;也方便后续操作&#xff0c;将IP地址赋值给一个变…...

纯血鸿蒙APP实战开发——手写绘制及保存图片

介绍 本示例使用drawing库的Pen和Path结合NodeContainer组件实现手写绘制功能。手写板上完成绘制后&#xff0c;通过调用image库的packToFile和packing接口将手写板的绘制内容保存为图片&#xff0c;并将图片文件保存在应用沙箱路径中。 效果图预览 使用说明 在虚线区域手写…...

在什么情况下表单会被重复提交?如何避免?

表单被重复提交是Web应用中常见的问题&#xff0c;通常在用户提交表单后点击按钮多次&#xff0c;或在表单提交后刷新页面时发生。这可能导致数据的重复处理&#xff0c;比如重复记录或订单。 何时会发生表单重复提交&#xff1f; 用户多次点击提交按钮&#xff1a;在网络延迟…...

JavaScript 中的 Class 类

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f525; 引言&#x1f3af; 基础知识&#x1f3d7;️ 构造函数 (Constructor)&#x1f510; 私有字段 (Private Fields)&#x1f510; 私有方法 (Private Methods)&#x1f9ec; 继承 (Inheritance)&#x1f4e6; 静态…...

python实验三 实现UDP协议、TCP协议进行服务器端与客户端的交互

实验三 实验题目 1、请利用生成器构造一下求阶乘的函数Factorial()&#xff0c;定义一个函数m()&#xff0c;在m()中调用生成器Factorial()生成小于100的阶乘序列存入集合s中&#xff0c;输出s。 【代码】 def factorial():n1f1while 1:​ f * n​ yield (f)​ n1…...

ServiceNow 研究:通过RAG减少结构化输出中的幻觉

论文地址&#xff1a;https://arxiv.org/pdf/2404.08189 原文地址&#xff1a;rag-hallucination-structure-research-by-servicenow 在灾难性遗忘和模型漂移中&#xff0c;幻觉仍然是一个挑战。 2024 年 4 月 18 日 灾难性遗忘&#xff1a; 这是在序列学习或连续学习环境中出现…...

ADS基础教程10-多态性(动态模型选择)

目录 一、多态性定义二、操作步骤&#xff11;.模型建立&#xff12;.模型选择&#xff13;.执行仿真 一、多态性定义 ADS中支持一个Symbol中&#xff0c;可以同时存在多个子图。在仿真时可以动态选择不同的子图继续宁仿真。 二、操作步骤 &#xff11;.模型建立 在上一章A…...

代码随想录第四十六天|单词拆分

题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;...

RabbitMQ的介绍和使用

1.同步通讯和异步通讯 举个例子&#xff0c;同步通讯就像是在打电话&#xff0c;因此它时效性较强&#xff0c;可以立即得到结果&#xff0c;但如果你正在和一个MM打电话&#xff0c;其他MM找你的话&#xff0c;你们之间是不能进行消息的传递和响应的 异步通讯就像是微信&#…...

前端get请求日期类型参数向后端传参失败

1、背景 get请求&#xff0c;通过url上传参&#xff0c;因此日期类型是string类型数据 2、异常信息 nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.time.LocalDate] for…...

【docker 】 push 镜像提示:denied: requested access to the resource is denied

往 Docker Registry &#xff08;私服&#xff09;push 镜像提示&#xff1a;denied: requested access to the resource is denied 镜像push 语法&#xff1a;docker push <registry-host>:<registry-port>/<repository>:<tag> docker push 192.16…...

浏览器各类好用插件使用及常见问题(技巧)总结

目录 Vimium C快捷键问题为什么Vimium C - 全键盘操作浏览器插件在百度页面中, x ,o,f等快捷键不起作用如何使用viminum c插件进行自定义快捷键?vimucm 为什么在浏览器首页时快捷键不起作用? 网页截图问题firefox 网页截图使用 idm问题浏览器点击idm 不下载? 待续、更新中 V…...

Python批量计算多张遥感影像的NDVI

本文介绍基于Python中的gdal模块&#xff0c;批量基于大量多波段遥感影像文件&#xff0c;计算其每1景图像各自的NDVI数值&#xff0c;并将多景结果依次保存为栅格文件的方法。 如下图所示&#xff0c;现在有大量.tif格式的遥感影像文件&#xff0c;其中均含有红光波段与近红外…...

6.k8s中的secrets资源

一、Secret secrets资源&#xff0c;类似于configmap资源&#xff0c;只是secrets资源是用来传递重要的信息的&#xff1b; secret资源就是将value的值使用base64编译后传输&#xff0c;当pod引用secret后&#xff0c;k8s会自动将其base64的编码&#xff0c;反编译回正常的字符…...

git 更换远程仓库地址三种方法总结

git 更换远程仓库地址三种方法总结 一、前言 由于私服的 gitlab 的地址变更&#xff0c;导致部分项目代码提交不上去&#xff0c;需要修改远端仓地址。 其它需要修改远程仓地址的情况如&#xff1a;切换git clone 协议由ssh变为https。 二、环境 windows 10git version 2.3…...

快速找出存(不存在)在某个(或多个)文件的文件夹

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 想要找出有下面这个文件存在的文件夹 切换到批量文件复制版块&#xff0c;快捷键Ctrl5 右侧&#xff0c;搜索添加 选定范围&#xff0c;勾选搜索文件夹、包…...

Linux USB转串口设备路径的查找方法

1、USB转串口设备 USB转串口设备是在嵌入式软件开发过程中经常要使用的&#xff0c;常常用于对接各种各样的串口设备。如果一台linux主机上使用多个usb转串口设备时&#xff0c;应用程序中就需要知道自己操作的是哪个串口设备。串口设备在系统上电时&#xff0c;由于驱动加载的…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁

赛门铁克威胁猎手团队最新报告披露&#xff0c;数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据&#xff0c;严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能&#xff0c;但SEMR…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...