栈的实现与OJ括号匹配

今日备忘录: "不破不立. "

本文索引

  • 1. 前言
  • 2. 顺序表与链表的区别
  • 3. 什么是栈
  • 4. 栈的实现
  • 5. OJ括号匹配
  • 6. 总结

1. 前言

人总是在坍塌中重建, 有些东西必须摧毁, 才能迎来新生, 不管是那些消耗你的人, 还是令你感到焦虑的事情, 还是一份你觉得毫无意义并且又不喜欢的工作, 又或者是那个内心敏感的自己, 总之你害怕什么, 就要去面对什么, 你想要什么, 就要去靠近什么, 在声色名利中守住本性, 在世俗目光中信步前行, 大浪淘沙, 去伪存真, 破而后立, 否极泰来.

本文旨在探讨数据结构中栈的实现以及顺序表与链表区别总结.
更多精彩, 期待关注 主页: 酷酷学!!!

2. 顺序表与链表的区别

在实现栈之前, 我们先总结一下顺序表和链表
在这里插入图片描述
以上是顺序表与链表比较全面的区别总结, 在插入数据时链表没有容量的概念指的是链表的空间是使用多少开辟多少, 不会进行扩容操作, 也不会造成容量的浪费.

那么什么是缓存利用率,简单讲解一下

在这里插入图片描述
以上是存储器的结构层次,由于CPU的访问速度非常的快, 它不会直接访问内存, 因为内存的读写速度太慢了, 而是将数据先逐层转移到寄存器或者高速缓存中,在进行读写, 一般寄存器存放字节大小为8的数据, 然后CPU再进行访问, 但是如何将数据转移到缓存当中的呢, 为什么说顺序表缓存利用率高而链表低呢?

在这里插入图片描述

在将内存中的数据运送到缓存中的时候, 不是一个一个传输的,而是将连带后面的一块空间直接一起运送到缓存中, 如同一辆大巴车一样, 不是一个一个运送, 而是包括后面的一块空间一起运输, 然后CPU在从缓存中进行读写, 那么, 如果继续往后读写, 在缓存中, 我们称之为缓存命中, 直接访问, 如果不在缓存中, 我们称之为不命中, 要把数据从内存加载到缓存中, 在进行访问, 如此看来所以 顺序表的缓存利用率肯定高于链表

更多资讯, 可以点击参考 与程序员相关的CPU缓存知识

3. 什么是栈

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

压栈 : 栈的插入操作叫做压栈或入栈, 入数据在栈顶
出栈 : 栈的删除操作叫做出栈. 出数据也在栈顶.

在这里插入图片描述
在这里插入图片描述

4. 栈的实现

栈的实现一般可以使用数组或者链表进行实现, 相对而言数组的结构实现更优一些, 因为在数组上尾插数据的代价比较小, 而且数组的缓存利用率比较高.

在这里插入图片描述
在这里插入图片描述
第一步:

创建三个文件
在这里插入图片描述
在头文件中进行结构定义和函数声明

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDatatype;
typedef struct Stack
{STDatatype* a;int top;int capacity;
}ST;//初始化
void InitStack(ST* pst);
//销毁
void Destory(ST* pst);//压栈
void Push(ST* pst,STDatatype x);
//出栈
void Pop(ST* pst);
//取栈顶元素
STDatatype STTop(ST* pst);//判空
bool Empty(ST* pst);
//获取元素个数
int Size(ST* pst);

第二步:
实现栈的方法

  • 初始化
void InitStack(ST* pst)
{assert(pst);pst->a = NULL;pst->capacity = pst->top = 0;
}

注意
top的值根据自己的情况定义, 若top=0,表示指向栈顶数据下一个位置, top=-1,表示指向栈顶数据.
在这里插入图片描述

首先断言,这里肯定不能给我传一个NULL, 然后进行常规操作

  • 销毁
void Destory(ST* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}

动态顺序表, 空间需要手动释放

  • 压栈
void Push(ST* pst, STDatatype x)
{assert(pst);if (pst->capacity == pst->top){int Newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDatatype* tmp = (STDatatype*)realloc(pst->a,sizeof(STDatatype) * Newcapacity);if (tmp == NULL){perror("malloc fail");return;}pst->a = tmp;pst->capacity = Newcapacity;}pst->a[pst->top] = x;pst->top++;
}

因为我们初始化的时候没有开辟空间, 所以如果栈为空的时候, 我们先开辟四个空间, 当栈满时, 我们在成倍扩容, 然后先用临时变量存储首地址, 防止申请失败原地址丢失, 然后更改空间容量大小, 最后在进行写入数据.

  • 销毁
void Pop(ST* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}

首先栈不能为NULL, 并且需要有数据, 然后直接top-- 就行.

  • 获取栈顶元素
STDatatype STTop(ST* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top-1];
}

直接返回top的前一个位置

  • 判断栈是否为空
bool Empty(ST* pst)
{assert(pst);return pst->top == 0;
}

如果top为0则栈为空

  • 获取数据个数
int Size(ST* pst)
{assert(pst);return pst->top;
}

top表示下标, 也就是元素个数

5. OJ括号匹配

题目链接: 有效的括号

题目描述:

在这里插入图片描述
题目分析:

首先题目有三个要求

  1. 左括号必须用相同类型的右括号进行闭合.
  2. 左括号必须以正确的顺序闭合
  3. 每个左括号都有一个对应相同类型的左括号

如果我们直接用左括号个数与右括号进行比较的话, 那么顺序问题我们无法解决, 而栈这种后进先出的结构恰好可以解决这种问题, 当遇到左括号时进行压栈, 遇到右括号时将左括号出栈, 进行比较, 正好解决了顺序问题, 但是C语言没有栈这种结构, 所以我们需要自己写栈这种结构.
于是我们很容易写出下面的代码.

bool isValid(char* s) {ST stack;InitStack(&stack);while (*s){//左括号压栈if (*s == '(' || *s == '{' || *s == '['){Push(&stack, *s);s++;}//右括号与栈顶左括号进行匹配else{char tmp = STTop(&stack);Pop(&stack);//如果不匹配if ((tmp == '(' && *s != ')')|| (tmp == '[' && *s != ']')|| (tmp == "{" && *s != '}')){return false;Destory(&stack);}}}return true;Destory(&stack);
}

但是这样写真的对吗, 答案是错的, 因为如果只有左括号的情况, 和只有右括号的情况, 我们还需要加以判断. 修正代码
字符串只有右括号, 先判断栈是否为空, 若为空返回false,并且释放栈

字符串只有左括号, 循环结束, 看看栈中元素还有没有, 如果还有则返回false,并且销毁栈

bool isValid(char* s) {ST stack;InitStack(&stack);while (*s) {// 左括号压栈if (*s == '(' || *s == '{' || *s == '[') {Push(&stack, *s);}// 右括号与栈顶左括号进行匹配else {if (Empty(&stack)) {Destory(&stack);return false;}char tmp = STTop(&stack);Pop(&stack);// 如果不匹配if ((tmp == '(' && *s != ')') || (tmp == '[' && *s != ']') ||(tmp == '{' && *s != '}')) {Destory(&stack);return false;}}++s;}bool ret = Empty(&stack);Destory(&stack);return ret;
}

全部代码如下:

typedef char STDatatype;
typedef struct Stack {STDatatype* a;int top;int capacity;
} ST;// 初始化
void InitStack(ST* pst);
// 销毁
void Destory(ST* pst);// 压栈
void Push(ST* pst, STDatatype x);
// 出栈
void Pop(ST* pst);
// 取栈顶元素
STDatatype STTop(ST* pst);// 判空
bool Empty(ST* pst);
// 获取元素个数
int Size(ST* pst);void InitStack(ST* pst) {assert(pst);pst->a = NULL;pst->capacity = pst->top = 0;
}void Destory(ST* pst) {assert(pst);free(pst->a);pst->a = NULL;pst->top = pst->capacity = 0;
}void Push(ST* pst, STDatatype x) {assert(pst);if (pst->capacity == pst->top) {int Newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;STDatatype* tmp =(STDatatype*)realloc(pst->a, sizeof(STDatatype) * Newcapacity);if (tmp == NULL) {perror("malloc fail");return;}pst->a = tmp;pst->capacity = Newcapacity;}pst->a[pst->top] = x;pst->top++;
}void Pop(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 Empty(ST* pst) {assert(pst);return pst->top == 0;
}int Size(ST* pst) {assert(pst);return pst->top;
}bool isValid(char* s) {ST stack;InitStack(&stack);while (*s) {// 左括号压栈if (*s == '(' || *s == '{' || *s == '[') {Push(&stack, *s);}// 右括号与栈顶左括号进行匹配else {if (Empty(&stack)) {Destory(&stack);return false;}char tmp = STTop(&stack);Pop(&stack);// 如果不匹配if ((tmp == '(' && *s != ')') || (tmp == '[' && *s != ']') ||(tmp == '{' && *s != '}')) {Destory(&stack);return false;}}++s;}bool ret = Empty(&stack);Destory(&stack);return ret;
}

6. 总结

栈是一种线性数据结构,具有后进先出(LIFO)的特点,即最后进入栈的元素最先被访问或删除。栈通常有两种基本操作:压栈(push)和弹栈(pop),分别用于将元素压入栈顶和从栈顶弹出元素。

栈的应用非常广泛,常见的应用包括表达式求值、函数调用、浏览器的前进后退功能等。在计算机科学中,栈也被用于实现递归算法、解决括号匹配等问题。

栈的实现方式有多种,包括基于数组和基于链表的实现。基于数组的实现通常需要指定栈的最大容量,而基于链表的实现则可以动态调整大小。

总的来说,栈是一种非常重要且常用的数据结构,掌握栈的基本操作和应用场景对于理解算法和数据结构有着重要的意义。

如果此文有帮助 感谢点赞关注!!!

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

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

相关文章

(车载)毫米波雷达信号处理中的恒虚警检测(CFAR)技术概述

说明 恒虚警检测(Constant False-Alarm Rate, CFAR)是雷达目标(信号)检测中很重要的一个概念&#xff0c;从事雷达相关科研或工程研发的或多或少应该都接触过。CFAR这项技术在工程实践上其实是比较简单的(至少在我了解的车载雷达领域)&#xff0c;不过这项技术也有很多可以深挖…

Ansys ACT的一个例子

由XML和IronPython文件组成&#xff0c;文件结构如下&#xff1a; ExtSample.xml <extension version"1" name"ExtSample1"><guid shortid"ExtSample1">2cc739d5-9011-400f-ab31-a59e36e5c595</guid><script src"sam…

10分钟了解Flink SQL使用

Flink 是一个流处理和批处理统一的大数据框架&#xff0c;专门为高吞吐量和低延迟而设计。开发者可以使用SQL进行流批统一处理&#xff0c;大大简化了数据处理的复杂性。本文将介绍Flink SQL的基本原理、使用方法、流批统一&#xff0c;并通过几个例子进行实践。 1、Flink SQL基…

【Linux】17. 进程间通信 --- 管道

1. 什么是进程间通信(进程间通信的目的) 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了…

Springboot自动装配源码分析

版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/> <!-- lookup parent from repository --> </par…

第六十节 Java设计模式 - 过滤器/标准模式

Java设计模式 - 过滤器/标准模式 过滤器模式使用不同的条件过滤对象。 这些标准可以通过逻辑操作链接在一起。 过滤器模式是一种结构型模式。 例子 import java.util.List; import java.util.ArrayList;class Employee {private String name;private String gender;private…

决策树学习记录

对于一个决策树的决策面&#xff1a; 他其实是在任意两个特征基础上对于所有的点进行一个分类&#xff0c;并且展示出不同类别的之间的决策面&#xff0c;进而可以很清楚的看出在这两个特征上各个数据点种类的分布。 对于多输出的问题&#xff0c;在利用人的上半张脸来恢复下半…

ICode国际青少年编程竞赛- Python-4级训练场-复杂嵌套for循环

ICode国际青少年编程竞赛- Python-4级训练场-复杂嵌套for循环 1、 for i in range(4):Dev.step(i6)for j in range(3):Dev.turnLeft()Dev.step(2)2、 for i in range(4):Dev.step(i3)for j in range(4):Dev.step(2)Dev.turnRight()Dev.step(-i-3)Dev.turnRight()3、 for i …

Windows关闭NGINX命令

1、首先用cmd进入NGINX的目录下,输入下面命令&#xff0c;查看nginx是否启动 tasklist /fi "imagename eq nginx.exe"2、关闭nginx taskkill /f /t /im nginx.exe3、启动&#xff1a;start nginx 4、重启&#xff1a;nginx -s reload

【牛客】SQL211 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary

1、描述 有一个薪水表salaries简况如下&#xff1a; 请你获取薪水第二多的员工的emp_no以及其对应的薪水salary&#xff0c; 若有多个员工的薪水为第二多的薪水&#xff0c;则将对应的员工的emp_no和salary全部输出&#xff0c;并按emp_no升序排序。 2、题目建表 drop table …

ctfshow 源码审计 web301--web305

web301 在checklogin.php 发现了 $sql"select sds_password from sds_user where sds_username".$username." order by id limit 1;";在联合查询并不存在的数据时&#xff0c;联合查询就会构造一个虚拟的数据就相当于构造了一个虚拟账户&#xff0c;可以…

MSMQ消息队列

MQ是一种企业服务的消息中间节技术&#xff0c;这种技术常常伴随着企业服务总线相互使用&#xff0c;构成了企业分布式开发的一部分&#xff0c;如果考虑到消息的发送和传送之间是可以相互不联系的并且需要分布式架构&#xff0c;则可以考虑使用MQ做消息的中间价技术&#xff0…

如何给远程服务器配置代理

目录 前言 正文 更换镜像源 开始之前 安装过程 遇到的问题 尾声 &#x1f52d; Hi,I’m Pleasure1234&#x1f331; I’m currently learning Vue.js,SpringBoot,Computer Security and so on.&#x1f46f; I’m studying in University of Nottingham Ningbo China&#x1f4…

TFN CK1840B 喇叭天线 定向 18GHz~40GHz

沃比得 CK1840B 喇叭天线 定向 18GHz~40GHz 产品概述 沃比得 CK1840B喇叭天线工作频率为 18GHz~40GHz。具有频带宽&#xff0c; 性能可靠&#xff0c; 增益高等优 点&#xff0c; 是理想的 EMC 测试、电子对抗等领域的定向接收、发射天线。 应用领域 ● 电子对抗领域 ● EM…

IT服务台的演变趋势

在技术进步和用户期望变化的推动下&#xff0c;IT服务台正在经历重大变化。IT服务台的未来将主要受到以下趋势的推动&#xff1a; 先进的人工智能和认知技术 预计高级人工智能 &#xff08;AI&#xff09; 和认知技术在 IT 服务台中的集成度会更高。通过将 IT 服务台集成到 IT…

PMC高手如何玩转跨部门协作?让团队和谐共生

PMC&#xff08;生产与物料控制&#xff09;作为连接生产与供应链的关键部门&#xff0c;其与其他部门之间的协作关系显得尤为重要。本文&#xff0c;深圳天行健精益管理咨询公司分享具体方法如下&#xff1a; 首先&#xff0c;PMC需要明确自己的角色定位。作为生产与供应链之间…

Redis经典问题:数据并发竞争

大家好,我是小米!今天我们要聊的话题是在大流量系统中常见的一个问题:数据并发竞争。不管是火车票系统还是微博系统,一旦出现数据并发竞争,都可能导致用户体验下降,甚至系统崩溃。那么,我们该如何解决这个问题呢?让我们一起来深入探讨! 数据并发竞争 当我们谈论大流…

三. TensorRT基础入门-ONNX注册算子的方法

目录 前言0. 简述1. 执行一下我们的python程序2.转换swin-tiny时候出现的不兼容op的例子3. 当出现导出onnx不成功的时候&#xff0c;我们需要考虑的事情4. unsupported asinh算子5. unsupported deformable conv算子总结参考 前言 自动驾驶之心推出的 《CUDA与TensorRT部署实战…

EmotiVoice 实时语音合成TTS

参考:https://github.com/netease-youdao/EmotiVoice 测试整体速度可以 docker安装: 运行容器:默认运行了两个服务,8501 一个streamlit页面,另外8000是一个api接口服务 docker run -dp 8501:8501 -p 8250:8000 syq163/emoti-voice:latest ##gpu运行 docker run --gpus a…

第四届微调——炼丹

学习地址&#xff1a;Tutorial/xtuner/README.md at main InternLM/Tutorial GitHub 笔记 微调是一种在已有的预训练模型基础上&#xff0c;通过使用新的数据对模型进行进一步优化和调整的技术手段。它的目的是使模型能够更好地适应特定的应用场景和任务需求&#xff0c;进一…