数据结构·一篇搞定栈!

好久不见,超级想念
废话不多说,直接看
请添加图片描述

引言

在数据结构的大家族中,栈(Stack)是一种非常重要的线性数据结构,它的特点是后进先出(LIFO,Last In First Out)。栈在程序设计中有着广泛的应用,比如函数调用栈、浏览器的前进后退功能等。本文将详细介绍栈的基本概念、操作以及使用C语言实现栈的方法。

栈的基本概念

栈是一种只能在一端(称为栈顶,top)进行插入和删除操作的线性表。在栈中,允许插入和删除的一端称为栈顶,另一端称为栈底(bottom)。栈没有后驱结点,插入和删除运算都只能在栈顶进行。

栈的实现

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

在这里插入图片描述

// 下面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈

typedef int STDataType;
#define N 10
typedef struct Stack
{STDataType _a[N];int _top; // 栈顶
}Stack;

我只做部分讲解,不太难哈哈哈

#include <stdio.h>  
#include <stdlib.h>  
#include <stdbool.h>  // 定义栈的数据类型  
typedef int STDataType;  // 定义栈的结构体  
typedef struct Stack  
{  STDataType* _a;  int _top; // 栈顶  int _capacity; // 容量  
} Stack;  // 初始化栈  
void StackInit(Stack* ps)  
{  ps->_a = NULL;  ps->_top = -1;  ps->_capacity = 0;  
}  
// 扩容栈  
void StackResize(Stack* ps, int newCapacity)  
{  STDataType* temp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newCapacity);  if (!temp)  {  exit(-1); // 内存分配失败,退出程序  }  ps->_a = temp;  ps->_capacity = newCapacity;  
}  

在函数中,首先通过realloc函数重新分配内存,将栈的数据数组_a扩充到新的容量newCapacity。realloc函数的第一个参数是原有的数据数组_a,第二个参数是新的容量newCapacity乘以每个元素的大小。

接着,将realloc返回的新内存地址赋值给临时指针变量temp。如果realloc函数分配内存失败,temp将为NULL。在这种情况下,通过if语句检查temp是否为NULL,如果是,则调用exit(-1)函数退出程序,表示内存分配失败。

如果realloc函数成功分配了新的内存空间,将临时指针temp指向的内存地址赋值给栈结构体指针ps的数据数组_a,以此来更新栈的数据数组。

最后,将新的容量newCapacity赋值给栈结构体指针ps的_capacity,表示栈的容量已经扩充到新的值。这样,栈就成功扩容了。

// 入栈  
void StackPush(Stack* ps, STDataType data)  
{  if (ps->_top == ps->_capacity - 1) // 栈满,扩容  {  int newCapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;  StackResize(ps, newCapacity);  }  ps->_a[++(ps->_top)] = data; // 先移动指针再赋值  
}  

在函数中,首先通过条件判断检查栈是否已满。判断条件为栈顶指针_top是否等于栈的容量_capacity减去1。如果栈已满,即栈顶指针指向了最后一个位置,则需要对栈进行扩容。

在扩容的部分,首先计算新的容量newCapacity。如果栈当前容量为0(即栈为空),则新容量设为4;否则新容量设为当前容量的两倍。接着调用StackResize函数,将栈结构体指针ps和新容量newCapacity作为参数,进行栈的扩容操作。

如果栈未满,或者扩容完成后,接着执行入栈操作。将要入栈的数据data存入栈的数据数组_a中,存储位置为栈顶指针_top的下一个位置,即++(ps->_top)。这里使用了前置递增运算符,先将栈顶指针_top加1,然后再将数据data存入该位置,表示先移动指针再赋值。

通过这段代码,实现了将数据入栈的功能,并在栈满时自动扩容,保证了栈的容量能够满足存储需求。

// 出栈  
void StackPop(Stack* ps)  
{  if (!StackEmpty(ps)) // 栈不为空  {  ps->_top--;  // 如果栈中元素过少,可以考虑缩容,这里省略  }  
}  // 获取栈顶元素  
STDataType StackTop(Stack* ps)  
{  if (!StackEmpty(ps))  {  return ps->_a[ps->_top];  }  return -1; // 栈为空,返回-1或其他错误标识  
}  // 获取栈中有效元素个数  
int StackSize(Stack* ps)  
{  return ps->_top + 1;  
}  // 检测栈是否为空,如果为空返回非零结果,如果不为空返回0  
int StackEmpty(Stack* ps)  
{  return ps->_top == -1;  
}  // 销毁栈  
void StackDestroy(Stack* ps)  
{  free(ps->_a);  ps->_a = NULL;  ps->_top = -1;  ps->_capacity = 0;  
}  int main()  
{  Stack s;  StackInit(&s);  // 入栈操作  StackPush(&s, 1);  StackPush(&s, 2);  StackPush(&s, 3);  // 获取栈顶元素  printf("栈顶元素为:%d\n", StackTop(&s));  // 出栈操作  StackPop(&s);  printf("出栈后,栈顶元素为:%d\n", StackTop(&s));  // 获取栈中有效元素个数  printf("栈中有效元素个数为:%d\n", StackSize(&s));  // 销毁栈  StackDestroy(&s);  return 0;  
}

在这里插入图片描述

例题

括号匹配

#define MAX_SIZE 10000typedef struct {char data[MAX_SIZE];int top;
} Stack;void initStack(Stack *stack) {stack->top = -1;
}bool isEmpty(Stack *stack) {return stack->top == -1;
}bool isFull(Stack *stack) {return stack->top == MAX_SIZE - 1;
}void push(Stack *stack, char c) {if (isFull(stack)) {printf("Stack overflow\n");} else {stack->data[++stack->top] = c;}
}char pop(Stack *stack) {if (isEmpty(stack)) {printf("Stack underflow\n");return '\0';} else {return stack->data[stack->top--];}
}bool isValid(char *s) {Stack stack;initStack(&stack);for (int i = 0; s[i] != '\0'; i++) {if (s[i] == '(' || s[i] == '{' || s[i] == '[') {push(&stack, s[i]);} else {if (isEmpty(&stack)) {return false;}char left = pop(&stack);if ((s[i] == ')' && left != '(') || (s[i] == '}' && left != '{') || (s[i] == ']' && left != '[')) {return false;}}}return isEmpty(&stack);
}

这段代码定义了一个基于数组的栈结构,并实现了栈的基本操作(初始化、判断是否为空、判断是否已满、压栈、弹栈),以及一个isValid函数,用于检查一个给定的字符串s中的括号是否有效。

栈的定义和操作

  1. 栈的定义:使用了一个结构体Stack,其中包含一个字符数组data(用于存储栈元素)和一个整数top(用于表示栈顶的位置)。
  2. 初始化:initStack函数将栈顶指针top初始化为-1,表示栈为空。
  3. 判断是否为空:isEmpty函数检查top是否为-1。
  4. 判断是否已满:isFull函数检查top是否等于MAX_SIZE - 1。
  5. 压栈:push函数在栈未满时将字符c压入栈中。
  6. 弹栈:pop函数在栈非空时弹出栈顶元素,并返回该元素。

isValid函数分析
isValid函数用于检查一个字符串s中的括号是否有效。它使用前面定义的栈结构,并遵循以下逻辑:

  1. 遍历字符串s中的每个字符。
  2. 如果遇到左括号((、{ 或 [),则将其压入栈中。
  3. 如果遇到右括号()、} 或 ]),则执行以下步骤:
    首先检查栈是否为空。如果为空,说明没有对应的左括号可以匹配,返回false。
    然后弹出栈顶元素(即最近压入的左括号),检查它是否与当前的右括号匹配。如果不匹配,返回false。
  4. 遍历完字符串后,如果栈为空,则说明所有括号都有效匹配,返回true;否则,返回false。

注意事项

  1. 代码中使用的MAX_SIZE定义了栈的最大容量,但请注意,这个值在实际使用中可能需要调整,以确保足够大以处理可能的输入字符串。
  2. pop函数在栈空时返回\0,这只是一个表示错误的标记。在实际应用中,可能还需要考虑其他错误处理机制。
  3. 字符串s只包含括号字符,没有考虑其他字符(如字母、数字或空格)。如果输入字符串包含这些字符,isValid函数可能无法正确工作。
  4. isValid函数只考虑了三种括号类型(圆括号、大括号和方括号),并且假设它们的匹配是成对出现的。如果输入字符串包含其他类型的括号或括号不成对出现,函数将无法正确工作。

那么看到这里,这篇小文章就快结束了哦
不要忘了今天是母亲节,大家不要忘了问候自己的妈妈哦,嘻嘻嘻
在这里插入图片描述
那么各位,我们下期再见咯,今天没有预告哈哈哈

在这里插入图片描述

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

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

相关文章

Echarts旭日图的配置项,强大的层级关系展示图表。

ECharts中的旭日图&#xff08;Sunburst Chart&#xff09;是一种数据可视化图表&#xff0c;用于展示层级关系数据。它通常用于呈现树状结构或层级结构的数据&#xff0c;例如组织结构、文件目录结构、地理区域层级等。 旭日图通过圆形的方式展示数据的层级结构&#xff0c;每…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout 文章编号&…

算法day01

1、[283.移动零](https://leetcode.cn/problems/move-zeroes/) 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 解题思路&#xff1a; 双指针…

IT项目管理-小题计算【太原理工大学】

1.合同总价问题 问承包商的利润是&#xff1f; 实际利润目标利润&#xff08;目标成本-实际成本&#xff09;*卖方分担比例 解&#xff1a;10 000&#xff08;100 000 - 90 000&#xff09;* 0.2 12 000&#xff08;元&#xff09; 实际成本有时也写作最终成本&#xff0c;问承…

Ubuntu 24.04 LTS 安装 touchegg 开启触控板多指手势

文章目录 〇、概述一、安装 touchegg二、安装 gnome-shell 扩展 X11 Gestures三、安装可视化配置工具 touche 〇、概述 之前为了让笔记本支持多指手势&#xff0c;我安装的是 fusuma&#xff0c;安装教程详见 这篇文章 &#xff0c;考虑到 fusuma 安装过程繁琐且不支持可视化配…

Qt自定义控件--提升为

为什么要自定义控件 1&#xff0c;有复合小控件需要组合为一个整体控件时&#xff1b; 2&#xff0c;一个复合控件需要重复使用时&#xff1b; 实现 自定义控件文件 新增三个文件 关联不同组的控件 关联之前的准备工作 1&#xff0c;在主控件选择和子控件所有控件所在控件…

ISIS学习二——与OSPF相比的ISIS报文以及路由计算

目录 一.ISIS支持的网络类型 1.OSPF支持 2.ISIS支持 二.ISIS最优路径的选取 &#xff08;1&#xff09;.ISIS开销值设置 1.全局开销 2.接口开销 3.根据带宽设置开销 &#xff08;2&#xff09;.ISIS的次优路径 三.ISIS报文格式 1.ISIS专用报头——TLV 2.ISIS通用头…

LeetCode-2391. 收集垃圾的最少总时间【数组 字符串 前缀和】

LeetCode-2391. 收集垃圾的最少总时间【数组 字符串 前缀和】 题目描述&#xff1a;解题思路一&#xff1a;处理垃圾和路程单独计算。解题思路二&#xff1a;逆向思维&#xff0c;计算多走的路解题思路三&#xff1a;只记录&#xff0c;当前t需要计算几次 题目描述&#xff1a;…

计算机实战分享3:森林火灾预测分析可视化机器学习预测-完整数据代码-可直接运行

直接看实验数据和结果: 代码: from sklearn import preprocessing import random from sklearn.m

基于LLM的自行车道CAD

LLM&#xff08;大型语言模型&#xff09;是强大的工具。对于许多人来说&#xff0c;用语言表达愿望通常比浏览复杂的 GUI 更简单。 1、系统简介和环境搭建 urb-x.ch&#xff0c;这是一家专门从事自行车道建设的公司。轨道采用模块化构建块进行独特设计&#xff0c;可以通过多…

HCIP的学习(15)

第六章&#xff0c;BGP—边界网关协议 自治系统—AS ​ 定义&#xff1a;由一个单一的机构或组织所管理的一系列IP网络及其设备所构成的集合。 ​ AS的来源&#xff1a; 整个网络规模过大&#xff0c;会导致路由信息收敛速度过慢&#xff0c;设备对相同目标认知不同。AS之间…

全国院校及梯度排序深度解析课(免费下载-帮助更多高考生做出人生重要的选择。)

"全国院校及梯度排序深度解析课"旨在深入探讨全国院校的排名及梯度排序原理。通过系统解析各院校的学术声誉、师资力量、科研水平等因素&#xff0c;帮助学员全面了解院校排名的背后逻辑&#xff0c;为选择合适院校提供理论支持。 课程大小&#xff1a;7G 课程下载…

Java面试之分布式篇

分布式锁的实现方案 &#xff08;1&#xff09;用数据库实现分布式锁比较简单&#xff0c;就是创建一张锁表&#xff0c;数据库对字段作唯一性约束。加锁的时候&#xff0c;在锁表中增加一条记录即可&#xff1b;释放锁的时候删除锁记录就行。如果有并发请求同时提交到数据库&…

css-页面布局-定位大解析-每文一言(世界上,没有人可以支持你一辈子)

&#x1f390;每文一言 世界上,没有人可以支持你一辈子 目录 &#x1f390;每文一言 &#x1f381;css定位 &#x1f9e7;静态定位 position: static &#x1f384;相对定位 position:relative &#x1f380;绝对定位 position:absolute &#x1f383;固定定位 position…

Yoast SEO Premium插件下载,提升您的网站SEO排名

在当今数字化时代&#xff0c;网站的搜索引擎优化&#xff08;SEO&#xff09;至关重要。它不仅影响着网站的可见度&#xff0c;更直接关系到您的在线业务成功与否。如果您正在寻找一个能够显著提升网站SEO表现的工具&#xff0c;Yoast SEO Premium插件将是您的理想选择。 为什…

(docker)进入容器后如何使用本机gpu

首次创建容器&#xff0c;不能直接使用本机gpu 在系统终端进行如下配置&#xff1a; 1.安装NVIDIA Container Toolkit 进入Nvidia官网Installing the NVIDIA Container Toolkit — NVIDIA Container Toolkit 1.15.0 documentation&#xff0c;安装NVIDIA Container Toolkit …

AI预测福彩3D采取887定位策略+杀断组+杀和尾+杀和值012缩水测试5月12日预测第1弹

前段时间工作太忙&#xff0c;手头上各种事情较多&#xff0c;没有静下心来对我的AI模型预测结果进行进一步分析筛选&#xff0c;导致最近连续几期与实际开奖结果相差较大。当然&#xff0c;客观来说&#xff0c;搞6码定位的确难度比较大&#xff0c;昨天跟几个常年研究3D的彩友…

【RAG 论文】FiD:一种将 retrieved docs 合并输入给 LM 的方法

论文&#xff1a; Leveraging Passage Retrieval with Generative Models for Open Domain Question Answering ⭐⭐⭐⭐ EACL 2021, Facebook AI Research 论文速读 在 RAG 中&#xff0c;如何将检索出的 passages 做聚合并输入到生成模型是一个问题&#xff0c;本文提出了一…

java基础知识点总结2024版(8万字超详细整理)

java基础知识点总结2024版&#xff08;超详细整理&#xff09; 这里写目录标题 java基础知识点总结2024版&#xff08;超详细整理&#xff09;java语言的特点1.简单性2.面向对象3.分布式4.健壮性5.安全性6.体系结构中立7.可移植性8.解释性9.多线程10.动态性 初识java中的main方…

Java类与对象(一)

类的定义与使用 在Java中使用关键字class定义一个类&#xff0c;格式如下&#xff1a; class 类名{// 成员变量/字段/属性//成员方法/行为 }Java中类和c语言中的结构体有点类似&#xff0c; 在Java中类名一般采用大驼峰&#xff08;每个首字母大写&#xff09;的形式&#xf…