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

数据结构(5)——栈

目录

前言

一、栈的概念及其结构

二、栈的实现

2.1说明

2.2动态栈结构体定义

2.3初始化

2.4销毁

2.5进(压)栈

2.6检验栈是否为空

2.7弹(出)栈

2.8栈的元素个数

2.9访问栈顶元素

三、运行

总结


前言

栈是一种常见的数据结构,其主要作用是存储和管理数据。栈遵循先进后出(FILO)的原则,即最后入栈的元素最先出栈。栈通常用于临时存储数据、函数调用和表达式求值等场景。


一、栈的概念及其结构

栈,是一种特殊的线性表,其只允许在固定的一段进行插入和删除元素操作。进行数据插入和删除操作的一段叫做栈顶,而另一端就叫栈尾。栈中保持着先进后出,后进先出(Last IN First Out)的原则。

可以理解为往一个盒子里放东西先放的东西放在最底下,后来放的东西在最上面,拿的时候也就是先拿最上面的东西。

 往里放的操作就是进栈,而往外取的操作就是出栈(弹栈)。

入栈顺序是1,2,3,4,出栈顺序也可以是1, 2, 3, 4,因为没有规定什么时候出栈,这样就是边进边出。很有意思。

二、栈的实现

2.1说明

栈的实现可以用数组实现,也可以用链表实现,但数组其实是最香的,数组从左到右往栈顶走,唯一的弊端就是有时候会要开辟空间申请内存。用链表的话,就用单链表,因为头插效率很高,所以单链表左端为栈顶,右端为栈低。

另外,栈也分动态的栈或者静态的栈,一般动态的栈用的比较多,而且比较方便。接下来我们来实现一个栈,用一个动态数组实现,其实栈的实现比较简单。

我们要实现的内容如下:

//定义结构体
typedef struct Stack
//初始化
void STInit(ST* ps);
//销毁
void STDestroy(ST* ps);
//压栈
void STPush(ST* ps, STDataType x);
//弹栈
void STPop(ST* ps);
//栈的元素个数
int STSize(ST* ps);
//检验栈是否为空
bool STEmpty(ST* ps);
//访问栈顶元素
STDataType STTop(ST* ps);

2.2动态栈结构体定义

//动态栈
typedef int STDataType;typedef struct Stack
{STDataType* a;int top;//下标int capacity;
}ST;

动态栈的结构体定义就是以上,一个块内有一个数据域,然后定义一个下标,用来实现后续的操作,还有当前数组的容量,后续可以对其实现更新。数据类型用typedef来定义。

2.3初始化

栈的初始化就是对结构体成员进行初始化,首先要检查结构体所创建的示例有没有,然后这个实例可以用来存储结构体中定义的各个成员变量的值。

//初始化
void STInit(ST* ps)
{assert(ps);ps->a =(STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){perror("ps->a malloc is error::");return;}ps->capacity = 4;//空间为4ps->top = 0;//如果赋值为0的话,这里top就是是下一个要放的数据的下标,也就是栈顶元素的下一个位置//ps->top = -1;//如果赋值为-1,那么就是栈顶元素的位置
}

因为我们要用一个动态数组实现,所以这里用malloc函数来申请4个空间大小的数据位置,对其进行检查,之后定义容量为4,这里top是下标,如果为0,那么就是栈顶下一个元素的位置,这里可能有点小难理解,我们可以想象现在栈里面啥都没有,而我们要放数据,数据放在哪里呢,第一个肯定是放在下标为0的位置,所以当top为0的时候,就是下一个数据要放的位置的下标,而如果我们要放在-1的位置,那么就是当前位置(栈顶元素的位置)。

2.4销毁

销毁栈,因为我们这里栈是用数组来实现的,所以当我们要销毁栈的时候,相当于把数组销毁,也就是结构体成员a。

//销毁
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;
}

注意这里销毁可以给a赋为空,其它的成员函数赋值为0。

2.5进(压)栈

进栈当然是含有两个参数,一个是栈的实例,另一个是要进入的数据。这里要注意的地方就是空间的大小,如果空间被占满了,就实现扩容。

//压栈
void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity){STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * ps->capacity * 2);if (tmp == NULL){perror("tmp realloc is error::");return;}else ps->a = tmp;ps->capacity *= 2;}ps->a[ps->top] = x;ps->top++;
}

代码中扩容使用realloc进行扩容,每一次是上一次容量的2倍,然后把数据存到下标为top的位置,top往后加加。

2.6检验栈是否为空

我们写这个函数的目的是为了规范,把每一个功能都可以用函数来实现,一目了然。

/检验栈是否为空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}

检验是否为空就是检查ps->top是否为0,如果为0的话,代表当前存的下一个数据的位置下标为0,就相当于里面并没有压入数据,真为1,假为0。

2.7弹(出)栈

出栈好出啊,就相当于把top--就可以了。当然这里用assert检验一下栈是否有实例和栈是否为空。

//弹栈
void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;
}

2.8栈的元素个数

返回栈的元素个数也十分的简单,我们知道,top代表的是下一个数据的下标,而我们起始的位置为0,所以虽然top后来又++了,但正好是栈中元素的数量。所以直接返回top就可以。

//栈的元素个数
int STSize(ST* ps)
{assert(ps);return ps->top;
}

2.9访问栈顶元素

我们知道栈只能先进后出,后进先出,所以访问元素只能在栈顶访问,通过弹栈+访问就可以实现对栈中每一个数据的访问。

//访问栈顶元素
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}

当然,这里还是要对栈进行检验,是否为空,实例是否存在,然后返回对应栈顶下标的元素。由于top是代表下一个元素的下标,所以栈顶元素的真正下标为当前top-1。

三、运行

这里我们写一个main函数来验证一下我们之前的函数。

#include"Stack.h"int main()
{ST st;STInit(&st);STPush(&st, 1);STPush(&st, 2);STPush(&st, 3);STPush(&st, 4);STPush(&st, 5);STPush(&st, 6);//不能直接打印printf("数量:%d \n", STSize(&st));printf("栈::");while (!STEmpty(&st)){printf("%d ",STTop(&st));STPop(&st);}STDestroy(&st);return 0;
}

如果不运行,阅读上面的代码就是,依次进栈1,2,3,4,5,6,然后打印出栈中元素的个数,打印不能直接打印,应该先访问当前栈顶元素,之后再弹栈,这样栈顶就会往下走一个,反复就可以实现访问栈中每一个元素的目的,应该是6,5,4,3,2,1,最后调用了销毁函数,结束返回0。

我们可以运行一下,运行结果:


总结

这篇文章很详细地介绍了栈的概念、结构以及实现,同时提供了栈的各种操作函数的代码实现。通过这些函数,可以实现栈的初始化、销毁、压栈、弹栈、获取栈元素个数、检验栈是否为空以及访问栈顶元素等功能。文章中的代码示例也展示了如何使用这些函数来对一个栈进行操作,包括进栈、出栈、获取栈中元素个数以及访问栈顶元素等操作。

总体而言,这篇文章对栈的基本概念和实现进行了很好的介绍,对于想要了解栈及其实现细节的读者来说,是一份很有帮助的参考材料。

相关文章:

数据结构(5)——栈

目录 前言 一、栈的概念及其结构 二、栈的实现 2.1说明 2.2动态栈结构体定义 2.3初始化 2.4销毁 2.5进(压)栈 2.6检验栈是否为空 2.7弹(出)栈 2.8栈的元素个数 2.9访问栈顶元素 三、运行 总结 前言 栈是一种常见的…...

Css径向渐变 - radial-gradient

由background-image: radial-gradient(at 75% 7%, blue 0px, transparent 50%);引出: 一、径向渐变是什么 径向渐变是颜色从一个中心点向外扩散的变化过程。 二、radial-gradient 函数是什么 1、使用语法: background-image: radial-gradient(shape si…...

理解激活函数,多个网络层之间如何连接

1. 激活函数如何在两个层之间作用 如果不在两个层之间添加激活函数,模型将无法学习非线性关系,表现出像线性模型一样的局限性。 LeakyReLU(0.2) 是一个激活函数,它的作用是对每一层的输出进行非线性转换。激活函数通常在神经网络中用于增加网…...

HTML5 Canvas绘画板项目实战:打造一个功能丰富的在线画板

HTML5 Canvas绘画板项目实战:打造一个功能丰富的在线画板 这里写目录标题 HTML5 Canvas绘画板项目实战:打造一个功能丰富的在线画板项目介绍技术栈核心功能实现1. 画板初始化与工具管理2. 多样化绘画工具3. 事件处理机制 技术要点分析1. Canvas上下文优化…...

2025亲测有用 yolov8 pt转onnx转ncnn 部署安卓

参考文章:pt转onnx转ncnn模型(yolov8部署安卓)_best.pt 转ncnn模型-CSDN博客 Yolov8-Ncnn模型部署Android,实现单一图片识别_yolov8转ncnn-CSDN博客 onnx转化为ncnn这条路径现在已经落后了,更多的是通过pnnx转化为nc…...

cursor的.cursorrules详解

文章目录 1. 文件位置与作用2. 基本语法规则3. 常用规则类型与示例3.1 忽略文件/目录3.2 限制代码生成范围3.3 自定义补全建议3.4 安全规则 4. 高级用法4.1 条件规则4.2 正则表达式匹配4.3 继承规则 5. 示例文件6. 注意事项 Cursor 是一款基于 AI 的智能代码编辑器,…...

MySQL 入门大全:运算符

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,…...

Oracle数据库数据编程SQL<3.6 PL/SQL 包(Package)>

包是Oracle数据库中一种重要的PL/SQL程序结构,它将逻辑相关的变量、常量、游标、异常、过程和函数组织在一起,提供了更好的封装性和模块化。在大型项目中,可能有很多模块,而每一个模块又有自己的存过、函数等。而这些存过、函数默认是放在一起的,如果所有的存过函数都是放…...

Rust 语言语法糖深度解析:优雅背后的编译器魔法

之前介绍了语法糖的基本概念和在C/Python/JavaScript中的使用,今天和大家讨论语法糖在Rust中的表现形式。 程序语言中的语法糖:让代码更优雅的甜味剂 引言:语法糖的本质与价值 语法糖(Syntactic Sugar) 是编程语言中那些并不引入新功能&…...

React-Markdown详解

React-Markdown 详解(2025年最新实践指南) 一、核心特性与架构解析 React-Markdown 是一个基于 React 的 Markdown 渲染组件库,其核心设计理念是通过 Unified 生态系统实现安全、可扩展的 Markdown 解析。关键特性包括: 安全渲染…...

uniapp 微信小程序 使用ucharts

文章目录 前言一、组件功能概述二、代码结构分析2.1 模板结构 总结 前言 本文介绍一个基于 Vue 框架的小程序图表组件开发方案。该组件通过 uCharts 库实现折线图的绘制,并支持滚动、缩放、触摸提示等交互功能。文章将从代码结构、核心方法、交互实现和样式设计等方…...

mysql中将外部文本导入表中过程出现的错误及解决方法

问题一: MySQL Loading local data is disabled; this must be enabled on both the client and server sides (MySQL加载本地数据被禁用;这必须在客户端和服务器端同时启用) 解决方法: 1,依次输入以下命令…...

C#实现HiveQL建表语句中特殊数据类型的包裹

用C#实现搜索字符串中用’(‘和’)‘包裹的最外层的里面里面的字符串&#xff0c;将里面的记录按一个或多个空格、换行或tab&#xff0c;或者是它的在一起的组合作为分隔&#xff0c;分隔出多个字符串组&#xff0c;如果组中有字符串中同时包含’<‘和’>’&#xff0c;则…...

【idea】实用插件

SonarLint SonarLint&#xff1a;代码质量扫描工具 使用 SonarLint 可以帮助我们发现代码的问题,并且还提供了相应的解决方案. 对于每一个问题&#xff0c;SonarLint 都给出了示例&#xff0c;还有相应的解决方案&#xff0c;教我们怎么修改&#xff0c;极大的方便了我们的开发…...

关于mysql 数据库中的 慢SQL 的详细分析,包括定义、原因、解决方法及表格总结

以下是关于 慢SQL 的详细分析&#xff0c;包括定义、原因、解决方法及表格总结&#xff1a; 1. 什么是慢SQL&#xff1f; 定义&#xff1a; 慢SQL 是指执行时间超过预设阈值&#xff08;如 2 秒&#xff09;的 SQL 语句&#xff0c;通常会导致数据库响应延迟、资源占用过高&am…...

uniapp选择文件使用formData格式提交数据

1. Vue实现 在vue项目中,我们有个文件,和一些其他字段数据需要提交的时候,我们都是使用axios 设置请求头中的Content-Type: multipart/form-data,然后new FormData的方式来进行提交。方式如下: const sendRequest = () => {const formData = new FormData()formData…...

蓝牙数字音频和模拟音频优劣势对比?

蓝牙模块中我们常说的模拟音频和数字音频&#xff0c;是指两种不同的信号处理技术&#xff0c;它们都可以实现声音的录制、存储、编辑、压缩或播放&#xff0c;但也有一些区别和特点。本文将为您深入解析蓝牙数字音频和模拟音频的一些常见区别。 数字音频&#xff1a; 蓝牙数…...

WiFi(无线局域网)技术的多种工作模式

WiFi&#xff08;无线局域网&#xff09;技术支持多种工作模式&#xff0c;以满足不同的网络需求和应用场景。以下是主要的WiFi工作模式及其详细说明&#xff1a; 1. 基础设施模式&#xff08;Infrastructure Mode&#xff09; [无线接入点 (AP)]/ | \ [客户端…...

基于OpenCV的指纹验证:从原理到实战的深度解析

指纹识别的技术革命与OpenCV的轻量级方案 在生物特征识别领域&#xff0c;指纹识别始终以独特性和稳定性占据核心地位。随着OpenCV等开源视觉库的普及&#xff0c;这项看似"高大上"的技术正逐步走向民用化开发。本文将突破传统算法框架&#xff0c;提出一套基于OpenC…...

VMware+Ubuntu+VScode+ROS一站式教学+常见问题解决

目录 一.VMware的安装 二.Ubuntu下载 1.前言 2.Ubuntu版本选择 三.VMware中Ubuntu的安装 四.Ubuntu系统基本设置 1.中文更改 2.中文输入法更改 3. 辅助工具 vmware tools 五.VScode的安装ros基本插件 1.安装 2.ros辅助插件下载 六.ROS安装 1.安装ros 2.配置ROS…...

音视频(一)ZLMediaKit搭建部署

前言 一个基于C11的高性能运营级流媒体服务框架 全协议支持H264/H265/AAC/G711/OPUS/MP3&#xff0c;部分支持VP8/VP9/AV1/JPEG/MP3/H266/ADPCM/SVAC/G722/G723/G729 1&#xff1a;环境 ubuntu22.* ZLMediaKit downlaod:https://github.com/ZLMediaKit/ZLMediaKit or https://g…...

leetcode25.k个一组翻转链表

思路源自 【力扣hot100】【LeetCode 25】k个一组翻转链表&#xff5c;虚拟节点的应用 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(in…...

配置 UOS/deepin 系统远程桌面,实现多台电脑协同办公

由于开发工作的需要&#xff0c;我的办公桌上目前有多台电脑。一台是 i7 配置的电脑&#xff0c;运行 UOS V20 系统&#xff0c;作为主力办公电脑&#xff0c;负责处理企业微信、OA 等任务&#xff0c;并偶尔进行代码编译和验证软件在 UOS V20 系统下的兼容性&#xff1b;另一台…...

配置Next.js环境 使用vscode

配置 Next.js 的开发环境其实非常简单&#xff0c;下面是一个从零开始的完整步骤&#xff0c;适用于 Windows、macOS 和 Linux&#xff1a; ✅ 一、准备工作 确保你已经安装了以下软件&#xff1a; 1. Node.js&#xff08;推荐 LTS 版本&#xff09; 官网&#xff1a;https:/…...

Vite相关知识点

一、自动导入vue vue-router pinia 1、安装unplugin-auto-import npm install unplugin-auto-import -D 2、引入 import AutoImport from unplugin-auto-import/vite; 3、配置vite.config.ts plugins: [ vue(), vueDevTools(), AutoImport({ include: [ /…...

RCE复现

1.过滤flag <?php error_reporting(0); if(isset($_GET[c])){$c $_GET[c];if(!preg_match("/flag/i", $c)){eval($c);}}else{highlight_file(__FILE__);代码审计过滤了"flag"关键词&#xff0c;但限制较弱&#xff0c;容易绕过 ?csystem("ls&…...

电子电气架构 --- 域控制器和EE架构关系

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...

多输入多输出 | Matlab实现CPO-LSTM冠豪猪算法优化长短期记忆神经网络多输入多输出预测

多输入多输出 | Matlab实现CPO-LSTM冠豪猪算法优化长短期记忆神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现CPO-LSTM冠豪猪算法优化长短期记忆神经网络多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现CPO-LSTM冠豪猪算法优化长短期…...

使用PyTorch实现LeNet-5并在Fashion-MNIST数据集上训练

本文将展示如何使用PyTorch实现经典的LeNet-5卷积神经网络&#xff0c;并在Fashion-MNIST数据集上进行训练和评估。代码包含完整的网络定义、数据加载、训练流程及结果可视化。 1. 导入依赖库 import torch from torch import nn from d2l import torch as d2l 2. 定义LeNet…...

19_20 js es6

目录 ES6 一、let 和 const关键字 1.1 var 和 let const的区别&#xff1f; 1.2 let 和const的区别 1.3 关于块级作用域 二、箭头函数 2.1箭头函数的特点 2.2 箭头函数的特殊性 this的问题 arguments参数集合 2.3函数传递参数时的默认值 2.4 箭头函数使用的场景有哪…...