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

[c语言日寄]数据结构:栈

在这里插入图片描述

【作者主页】siy2333
【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是进阶开发者,这里都能满足你的需求!
【食用方法】1.根据题目自行尝试 2.查看基础思路完善题解 3.学习拓展算法
【Gitee链接】资源保存在我的Gitee仓库:https://gitee.com/siy2333/study


文章目录

    • 前言:
    • 栈的基本概念
    • 栈的实现
      • 初始化
      • 入栈
      • 出栈
      • 查看栈顶元素
      • 检查栈是否为空
      • 获取栈的大小
      • 销毁栈
    • 栈的应用场景
      • 函数调用
      • 表达式求值
      • 括号匹配
      • 浏览器的前进和后退功能
    • 栈的优缺点
    • 栈的优化
      • 预分配内存
      • 使用循环缓冲区
    • 栈的测试
    • 完整代码
      • 头文件
      • 源文件
    • 栈的总结


前言:

在计算机科学中,数据结构是组织和存储数据的方式,而栈(Stack)是其中一种非常基础且重要的数据结构。它遵循后进先出(Last In First Out,LIFO)的原则,就像一叠盘子,你只能在最上面添加或移除盘子。本文将深入探讨栈的原理、实现方式以及应用场景,帮助读者更好地理解和运用这一数据结构。

文末附带完整的带有标准注释的c语言头文件以及源文件


栈的基本概念

栈是一种线性数据结构,它只允许在表的一端进行插入和删除操作。这一端被称为栈顶(Top),而另一端被称为栈底(Bottom)。栈的基本操作包括:

  1. 入栈(Push):将一个元素添加到栈顶。
  2. 出栈(Pop):移除栈顶的元素。
  3. 查看栈顶元素(Top):获取栈顶元素的值,但不移除它。
  4. 检查栈是否为空(Empty):判断栈中是否还有元素。
  5. 获取栈的大小(Size):返回栈中元素的数量。

这些操作的实现方式会因具体的编程语言和数据结构设计而有所不同,但基本原理是一致的。

栈的实现

栈可以通过数组或链表来实现。在本文中,我们将重点介绍基于数组的栈实现,因为它更简单且易于理解。以下是基于数组的栈实现的关键点:

初始化

在使用栈之前,需要对其进行初始化。这通常包括分配内存空间、设置栈顶指针和栈的容量。在我们的代码示例中,栈的初始化函数STInit会为栈分配初始容量为4的内存空间,并将栈顶指针设置为0。

void STInit(ST* ps)
{assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){perror("malloc fail");return;}ps->capacity = 4;ps->top = 0; // The next position of the current stack top elementreturn;
}

入栈

当向栈中添加元素时,需要检查栈是否已满。如果栈已满,则需要扩容。扩容通常是通过分配更大的内存空间来实现的。在我们的代码中,当栈满时,会将栈的容量加倍。

void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top){STDataType* point = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);if (point == NULL){perror("realloc fail");return;}ps->a = point;ps->capacity *= 2;}ps->a[ps->top] = x;ps->top++;return;
}

出栈

出栈操作相对简单,只需要将栈顶指针减1即可。但在出栈之前,需要检查栈是否为空,以避免出现错误。

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

查看栈顶元素

查看栈顶元素的操作也很简单,只需要返回栈顶指针所指向的元素即可。同样,在执行此操作之前,需要检查栈是否为空。

STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}

检查栈是否为空

检查栈是否为空的操作可以通过比较栈顶指针是否为0来实现。

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

获取栈的大小

获取栈的大小的操作可以通过返回栈顶指针的值来实现。

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

销毁栈

在使用完栈后,需要对其进行销毁,以释放分配的内存空间。销毁栈的操作包括释放内存空间、将栈顶指针和容量设置为0。

void STDestory(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;return;
}

栈的应用场景

栈在计算机科学中有着广泛的应用,以下是一些常见的应用场景:

函数调用

在编程语言中,函数调用是通过栈来实现的。当一个函数被调用时,它的参数、返回地址和局部变量等信息会被压入调用栈中。当函数执行完毕后,这些信息会被弹出栈,程序会返回到调用函数的位置继续执行。

表达式求值

栈可以用于表达式的求值。例如,在计算后缀表达式时,可以使用一个栈来存储操作数。当遇到一个操作符时,从栈中弹出两个操作数,进行相应的运算,然后将结果压入栈中。当表达式计算完毕时,栈顶的元素就是表达式的值。

括号匹配

栈可以用于检查括号是否匹配。当遇到一个左括号时,将其压入栈中;当遇到一个右括号时,从栈中弹出一个左括号。如果在弹出左括号时栈为空,或者弹出的左括号与右括号不匹配,则说明括号不匹配。

浏览器的前进和后退功能

浏览器的前进和后退功能也可以通过栈来实现。当用户访问一个网页时,将该网页的地址压入一个栈中;当用户点击后退按钮时,从栈中弹出一个网页地址并跳转到该网页;当用户点击前进按钮时,将弹出的网页地址压入另一个栈中。

栈的优缺点

栈的优点包括:

  1. 简单易用:栈的实现相对简单,操作也容易理解。
  2. 高效:栈的基本操作(如入栈、出栈、查看栈顶元素等)的时间复杂度为O(1)。
  3. 适用范围广:栈在计算机科学中有着广泛的应用,如函数调用、表达式求值、回溯算法等。

然而,栈也有一些缺点:

  1. 容量限制:如果栈的容量有限,可能会出现栈溢出的情况。虽然可以通过动态扩容来解决这个问题,但动态扩容会增加时间和空间的开销。
  2. 只能在一端操作:栈只能在栈顶进行插入和删除操作,不能在其他位置进行操作。

栈的优化

虽然栈的基本操作已经非常高效,但在某些情况下,我们仍然可以通过一些优化手段来提高栈的性能。以下是一些常见的优化方法:

预分配内存

在初始化栈时,可以预分配一定量的内存空间,以减少动态扩容的次数。这可以提高栈的性能,但会增加内存的使用量。

使用循环缓冲区

循环缓冲区是一种特殊的数组结构,它可以循环使用内存空间。通过使用循环缓冲区,可以减少内存的分配和释放次数,从而提高栈的性能。

栈的测试

为了验证栈的正确性和性能,我们需要对其进行测试。以下是一个简单的测试程序,用于测试栈的基本操作:

#include"Stack.h"void Test1()
{ST head;STInit(&head);STPush(&head, 1);STPush(&head, 2);STPush(&head, 3);STPush(&head, 4);STPush(&head, 5);while (!STEmpty(&head)){printf("%d ", STTop(&head));STPop(&head);}printf("\n");return;
}int main()
{Test1();return 0;
}

在这个测试程序中,我们首先初始化了一个栈,然后依次向栈中添加了5个元素。接着,我们依次从栈中弹出元素,并打印出每个元素的值。最后,我们销毁了栈。

完整代码

头文件

#pragma once/**
* @file Stack.h
* @brief The header file of the Stack.
* @author siy2333
* @date 2025.5.11
*
* This header file defines the data structure and related operation functions of a Stack.
* Stack is a Last-In-First-Out (LIFO) data structure used for storing and managing data elements, supporting operations to add (push) and remove (pop) elements at the top, and is widely applied in program calling, expression evaluation, and other scenarios.
* Provides basic operations for adding, deleting, querying, and modifying.
*///Standard library header files included.
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>/**
* @brief The data types stored in the Stack.
*/
typedef int STDataType;/**
* @typedef struct Stack.
* @brief Structure definition of Stack.
*/
typedef struct Stack
{STDataType* a;		///< The pointer to the memory for the Stack.int top;			///< The next position of the current Stack top element.int capacity;		///< The size of capacity.
}ST;/**
* @brief Initialize Stack.
*/
void STInit(ST* ps);/**
* @brief Destory the Stack.
*/
void STDestory(ST* ps);/**
* @brief Store x in the top of the Stack.
*/
void STPush(ST* ps, STDataType x);/**
* @brief Delete x at the top of the Stack.
*/
void STPop(ST* ps);/**
* @brief return the capacity size of the Stack.
*/
int STSize(ST* ps);/**
* @brief Check whether the Stack is empty.
* @return If the Stack is empty, return 1; Otherwise, return 0.
*/
bool STEmpty(ST* ps);/**
* @brief Return the data at the top of the Stack.
* @return the data at the top of the Stack.
*/
STDataType STTop(ST* ps);

源文件

#include"Stack.h"/**
* @detailsThe faction use malloc to apply for 4 copies of memory for the Stack.The 0 will be store int the ps->top, it mean the next position of the current stack top element.The capacity will be set to 4.
* @warning ps mustn't be NULL.
*/
void STInit(ST* ps)
{assert(ps);ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);if (ps->a == NULL){perror("malloc fail");return;}ps->capacity = 4;ps->top = 0;		//The next position of the current stack top elementreturn;
}/**
* @details The faction will free the memory for the Stack;The top will be set to 0;The capacity will be set to 0.
* @warning ps mustn't be NULL.
*/
void STDestory(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = 0;ps->capacity = 0;return;
}/**
* @details The faction will check whether the Stack is full;If the Stack is full, it will use realloc() to double the capacity, and refresh the ps->capacity.It will store the x in the ps->a[top], and refresh the ps->top.
* @warning ps mustn't be NULL.
*/
void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top){STDataType* point = (STDataType*)realloc(ps->a,sizeof(STDataType) * ps->capacity * 2);if (point == NULL){perror("realloc fail");return;}ps->a = point;ps->capacity *= 2;}ps->a[ps->top] = x;ps->top++;return;
}/**
* @details The function will refresh the ps->top.
* @warning ps musn't be NULL;
* @warning The Stack mustn't be empty.
*/
void STPop(ST* ps)
{assert(ps);assert(!STEmpty(ps));ps->top--;return;
}/**
* @warning ps mustn't be NULL;
*/
int STSize(ST* ps)
{assert(ps);return ps->top;
}/**
* @warning ps mustn't be NULL;
*/
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}/**
* @warning ps musn't be NULL;
* @warning The Stack mustn't be empty.
*/
STDataType STTop(ST* ps)
{assert(ps);assert(!STEmpty(ps));return ps->a[ps->top - 1];
}

栈的总结

栈是一种非常基础且重要的数据结构,它遵循后进先出的原则。栈的基本操作包括入栈、出栈、查看栈顶元素、检查栈是否为空和获取栈的大小等。栈可以通过数组或链表来实现,其中基于数组的栈实现相对简单且易于理解。栈在计算机科学中有着广泛的应用,如函数调用、表达式求值、回溯算法等。虽然栈有一些缺点,但它的优点使其在许多场景下都非常有用。通过一些优化手段,我们可以进一步提高栈的性能。总之,栈是一种非常重要的数据结构,值得我们深入学习和研究。

希望本文对您理解栈有所帮助。如果您有任何问题或建议,欢迎在评论区留言讨论。

[专栏链接QwQ] :⌈c语言日寄⌋CSDN
[关注博主ava]:siy2333
感谢观看~ 我们下次再见!!

相关文章:

[c语言日寄]数据结构:栈

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…...

WEB安全--Java安全--LazyMap_CC1利用链

一、前言 该篇是基于WEB安全--Java安全--CC1利用链-CSDN博客的补充&#xff0c;上篇文章利用的是TransformedMap类&#xff0c;而CC链的原作者是利用的LazyMap类作为介质进行的触发。 所以本文将分析国外原作者在ysoserial commonscollections1中给出的CC1利用链。 二、回顾梳…...

【杂谈】-AI 重塑体育营销:从内容管理到创意释放的全面变革

AI 重塑体育营销&#xff1a;从内容管理到创意释放的全面变革 文章目录 AI 重塑体育营销&#xff1a;从内容管理到创意释放的全面变革1、加速从采集到推广的内容生命周期2、个性化粉丝体验3、以比赛速度分发体育内容4、让创作者在人工智能&#xff08;AI&#xff09;时代自由创…...

黑马k8s(六)

1.Deployment&#xff08;Pod控制器&#xff09; Selector runnginx 标签选择&#xff1a;会找pod打的标签 执行删除之后&#xff0c;pod也会删除&#xff0c;Terminating正在删除 如果想要访问其中的一个pod借助&#xff1a;IP地址端口号访问 假设在某一个瞬间&#xff0c;…...

【数据结构】二分查找(返回插入点)5.14

二分查找基础版 package 二分查找; public class BinarySearch { public static void main(String[] args) { // TODO Auto-generated method stub } public static int binarySearchBasic(int[] a,int target) { int i0,ja.length-1; //设置指针初值 while…...

如何设计一个二级缓存(Redis+Caffeine)架构?Redis 6.0多线程模型如何工作?

一、二级缓存&#xff08;RedisCaffeine&#xff09;架构设计 1. 设计目标 通过「本地缓存&#xff08;Caffeine&#xff09; 分布式缓存&#xff08;Redis&#xff09;」的分层结构&#xff0c;实现&#xff1a; 低延迟&#xff1a;热点数据本地缓存&#xff08;内存级访问…...

Java:logback-classic与slf4j版本对应关系

1、结论 logback-classic-1.2.x及以下版本&#xff0c;则适配的slf4j 1.0.x - 1.7.x logback-classic-1.3.x及以上版本&#xff0c;则适配的slf4j 1.8.x及以上 2、原因分析 &#xff08;1&#xff09;logback-classic-1.2.x及以下版本 通过org.slf4j.impl.StaticLoggerBinder初…...

【OpenGL学习】(一)创建窗口

文章目录 【OpenGL学习】&#xff08;一&#xff09;创建窗口 【OpenGL学习】&#xff08;一&#xff09;创建窗口 GLFW OpenGL 本身只是一套图形渲染 API&#xff0c;不提供窗口创建、上下文管理或输入处理的功能。 GLFW 是一个支持创建窗口、处理键盘鼠标输入和管理 OpenGL…...

AI大语言模型评测体系演进与未来展望

随着人工智能技术的飞速发展,大语言模型(LLMs)已成为自然语言处理领域的核心研究方向。2025年最新行业报告显示,当前主流模型的评测体系已从单一任务评估转向多维度、全链路的能力剖析。例如,《全球首个大语言模型意识水平”识商”白盒DIKWP测评报告》通过数据、信息、知识…...

微服务项目->在线oj系统(Java版 - 5)

相信自己,终会成功 微服务代码: lyyy-oj: 微服务 目录 C端代码 用户题目接口 修改后用户提交代码(应用版) 用户提交题目判题结果 代码沙箱 1. 代码沙箱的核心功能 2. 常见的代码沙箱实现方式 3. 代码沙箱的关键问题与解决方案 4. 你的代码如何与沙箱交互&#xff1f; …...

disryptor和rabbitmq

disryptor和rabbitmq Disruptor 是什么&#xff1f; Disruptor 是一个由 LMAX Exchange 开发的高性能、低延迟的进程内&#xff08;in-process&#xff09;并发编程框架/库。它最初是为了解决金融交易系统中高吞吐量、低延迟消息传递的需求而设计的。 核心特点和设计理念&am…...

HTTP与HTTPS协议的核心区别

HTTP与HTTPS协议的核心区别 数据传输安全性 HTTP采用明文传输&#xff0c;数据易被窃听或篡改&#xff08;如登录密码、支付信息&#xff09;&#xff0c;而HTTPS通过SSL/TLS协议对传输内容加密&#xff0c;确保数据完整性并防止中间人攻击。例如&#xff0c;HTTPS会生成对称加…...

Flink 并行度的设置

在 Apache Flink 中&#xff0c;并行度&#xff08;Parallelism&#xff09; 是控制任务并发执行的核心参数之一。Flink 提供了 多个层级设置并行度的方式&#xff0c;优先级从高到低如下&#xff1a; &#x1f9e9; 一、Flink 并行度的四个设置层级 层级描述设置方式Operator…...

【微服务】SpringBoot + Docker 实现微服务容器多节点负载均衡详解

目录 一、前言 二、前置准备 2.1 基本环境 2.2 准备一个springboot工程 2.2.1 准备几个测试接口 2.3 准备Dockerfile文件 2.4 打包上传到服务器 三、制作微服务镜像与运行服务镜像 3.1 拷贝Dockerfile文件到服务器 3.2 制作服务镜像 3.3 启动镜像服务 3.4 访问一下服…...

get请求使用数组进行传参

get请求使用数组进行传参,无需添加中括号 mvc接口要添加参数名&#xff0c;使用array承接。不能用list, 否则会报错 这里是用apifox模拟前端调用。 前端调用代码 // 根据项目ID和角色ID查询相关审批人 export function findRelativeApproverByProjectIdAndRoleId(roleIds, p…...

20. 自动化测试框架开发之Excel配置文件的IO开发

20.自动化测试框架开发之Excel配置文件的IO开发 一、核心架构解析 1.1 类继承体系 class File: # 文件基类# 基础文件验证和路径管理class ExcelReader(File): # Excel读取器# 实现Excel数据解析逻辑1.2 版本依赖说明 # 必须安装1.2.0版本&#xff08;支持xlsx格式&#…...

【MySQL成神之路】MySQL常用语法总结

目录 MySQL 语法总结 数据库操作 表操作 数据操作 查询语句 索引操作 约束 事务控制 视图操作 存储过程和函数 触发器 用户和权限管理 数据库操作 创建数据库&#xff1a; CREATE DATABASE database_name; 选择数据库&#xff1a; USE database_name; 删除数…...

Linux动静态库制作与原理

什么是库 库是写好的现有的&#xff0c;成熟的&#xff0c;可以复用的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能每个人的代码都从零开始&#xff0c;因此库的存在意义非同寻常。 本质上来说库是一种可执行代码的二进制形式&#xff0c;可以被操作系统…...

确保高质量的音视频通话,如何最大化利用视频带宽

在当今数字时代&#xff0c;音视频内容随处可见&#xff0c;对于开发者来说&#xff0c;理解互联网带宽变得至关重要。我们的在线体验质量&#xff0c;无论是观看高清电影还是演唱会直播&#xff0c;都严重依赖于互联网带宽的概念。在本文中&#xff0c;我们将揭示视频带宽的复…...

ffmpeg 把一个视频复制3次

1. 起因&#xff0c; 目的: 前面我写过&#xff0c;使用 python 把一个视频复制3次但是速度太慢了&#xff0c;我想试试看能否改进。而且我想换一种新的视频处理思路&#xff0c;并试试看速度如何。 2. 先看效果 效果就是能行&#xff0c;而且速度也快。 3. 过程: 代码 1…...

GPT/Claude3国内免费镜像站更新 亲测可用

无限次使用&#xff1a;无限制的提问次数&#xff0c;不设上限&#xff0c;随心所欲。 无需魔法、稳定流畅&#xff1a;操作简便&#xff0c;无需复杂设置&#xff0c;即可享受稳定流畅的服务。 手机和电脑均能用&#xff1a;轻松适配手机和电脑&#xff0c;使用体验更佳。 …...

AI自动化工作流:开启当下智能生产力的价值

举手之言&#xff1a;AI自动化工作流创造了什么呢&#xff1f; AI自动化工作流 &#xff0c;顾名思义&#xff0c;是将人工智能&#xff08;AI&#xff09;技术与自动化流程相结合&#xff0c;通过智能化的方式来完成复杂的任务和操作。简单来说&#xff0c;它就是利用AI的强大…...

stm32——EXTI外部中断

NVIC优先级分组 抢占优先级 可以进行中断嵌套的优先级&#xff0c;即可以不等上一个中断执行完成就进入下一个中断 响应优先级 决定中断发生的顺序&#xff0c;但不可嵌套 程序实现 对射式红外传感计次 #include "stm32f10x.h" // Device head…...

Python:操作Excel按行写入

Python按行写入Excel数据,5种实用方法大揭秘! 在日常的数据处理和分析工作中,我们经常需要将数据写入到Excel文件中。Python作为一门强大的编程语言,提供了多种库和方法来实现将数据按行写入Excel文件的功能。本文将详细介绍5种常见的Python按行写入Excel数据的方法,并附上…...

Redis进阶知识

Redis 1.事务2. 主从复制2.1 如何启动多个Redis服务器2.2 监控主从节点的状态2.3 断开主从复制关系2.4 额外注意2.5拓扑结构2.6 复制过程2.6.1 数据同步 3.哨兵选举原理注意事项 4.集群4.1 数据分片算法4.2 故障检测 5. 缓存5.1 缓存问题 6. 分布式锁 1.事务 Redis的事务只能保…...

Python机器学习笔记(二十三 模型评估与改进-网格搜索)

上一次学习了评估一个模型的泛化能力,现在继续学习通过调参来提升模型的泛化性能。scikit-learn中许多算法的参数设置,在尝试调参之前,重要的是要理解参数的含义。找到一个模型的重要参数(提供最佳泛化性能的参数)的取值是一项棘手的任务,但对于几乎所有模型和数据集来说…...

12.vue整合springboot首页显示数据库表-实现按钮:【添加修改删除查询】

vue整合springboot首页显示数据库表&#xff1a;【添加修改删除查询】 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是node.js和vue的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系…...

bisheng系列(一)- 本地部署(Docker)

目录 一、导读 二、说明 1、镜像说明 2、本节内容 三、docker部署 1、克隆代码 2、运行镜像 3、可能的错误信息 四、页面测试 1、注册用户 2、登陆成功 3、添加模型 一、导读 环境&#xff1a;Ubuntu 24.04、Windows 11、WSL 2、Python 3.10 、bisheng 1.1.1 背景…...

如何用Python批量解压ZIP文件?快速解决方案

如何用Python批量解压ZIP文件&#xff1f;快速解决方案 文章目录 **如何用Python批量解压ZIP文件&#xff1f;快速解决方案**代码结果详细解释 话不多说&#xff0c;先上干货&#xff01;&#xff01;&#xff01; 代码 import os import zipfiledef unzip_file(dir_path: str…...

DriveGenVLM:基于视觉-语言模型的自动驾驶真实世界视频生成

《DriveGenVLM: Real-world Video Generation for Vision Language Model based Autonomous Driving》2024年8月发表&#xff0c;来自哥伦比亚大学的论文。 自动驾驶技术的进步需要越来越复杂的方法来理解和预测现实世界的场景。视觉语言模型&#xff08;VLM&#xff09;正在成…...