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

数据结构总结分享02——栈的相关例题与应用【简单】

前情提要

栈的应用非常广泛,下面列举出几个最为经典的题目,分别用了上篇文章中自己的类来实现以及 STL 中的std::stack来实现~

使用自己的类的应用

  • 题目:括号匹配
  • 说明:这是一个非常经典的栈新手村入门第一题,题目要求我们判断一个表达式的括号是否匹配成功。那不匹配的场景有哪些呢?包括一下几种场景:
    • 左 / 右括号多了,即最后会剩下未匹配的括号
    • 匹配不对:显然括号得跟自己一类的进行判断,比如([)]这种虽然满足了一个左括号匹配一个右括号,但是类型不对,依然错误。
      • 拓展:其实这道题还可以简化为表达式满足左右类型一定相同或只用一类括号时,那此时不匹配的清空就只会是左 / 右括号多了这种场景,那么此时就只需记录左右括号的个数,遍历完后再看个数是否想等即可
  • 拓展:一般来说编写这个程序都是来判断一个表达式的括号是否匹配,但我们还可以应用到对常规代码的括号匹配的正确性判断的应用中。因为据我们都所知的,代码语句除了应用之外,括号也都是满足表达式一样的配对原则因此代码功能可以直接复用~
  • 程序示例:
#include<iostream>#include<string>usingnamespacestd;// 定义泛型链式栈 (LStack)template<typenameT>classLStack{private:structNode{T data;Node*next;};Node*topPtr;// 栈顶指针public:// 构造函数LStack(){topPtr=nullptr;}// 析构函数:释放所有节点内存~LStack(){while(!isEmpty()){pop();}}// 入栈voidpush(T value){Node*newNode=newNode;newNode->data=value;newNode->next=topPtr;topPtr=newNode;}// 出栈Tpop(){if(isEmpty()){throwout_of_range("栈空,无法出栈");}Node*temp=topPtr;T poppedValue=temp->data;// 暂存要返回的数据topPtr=topPtr->next;deletetemp;// 释放内存returnpoppedValue;// 返回出栈的数据}// 判断栈是否为空boolisEmpty(){returntopPtr==nullptr;}};// 第二部分:括号匹配逻辑函数boolMatchBrackets(string str){LStack<char>lStack;for(inti=0;i<str.length();i++){// 遇到左括号:压入栈if(str[i]=='{'||str[i]=='['||str[i]=='('){lStack.push(str[i]);}// 遇到右括号:进行匹配检测elseif(str[i]=='}'||str[i]==']'||str[i]==')'){// 栈为空,说明右括号多出来了if(lStack.isEmpty()){cout<<"无匹配左括号 (位置 "<<i<<" 出现多余的 '"<<str[i]<<"')\n";// 【修复4】补充缺失的分号returnfalse;}// 取出栈顶最近的一个左括号charb=lStack.pop();// 判断是否配对if(!((b=='('&&str[i]==')')||(b=='['&&str[i]==']')||(b=='{'&&str[i]=='}'))){cout<<"匹配不对 (期待与 '"<<b<<"' 匹配,但遇到了 '"<<str[i]<<"')\n";returnfalse;}}}// 字符串遍历完了,如果栈里还有东西,则说明左括号多出来了if(!lStack.isEmpty()){cout<<"有未匹配的左括号\n";returnfalse;}else{cout<<"匹配成功\n";returntrue;}}// 测试intmain(){cout<<"--- 括号匹配测试程序 ---\n\n";// 完全匹配string test1="{[()]}";cout<<"测试 1: "<<test1<<endl;MatchBrackets(test1);cout<<endl;// 代码中常见的匹配string test2="int main() { int a = (1 + 2) * [3]; }";cout<<"测试 2: "<<test2<<endl;MatchBrackets(test2);cout<<endl;// 右括号多余string test3="{[()]} )";cout<<"测试 3: "<<test3<<endl;MatchBrackets(test3);cout<<endl;// 左右括号不匹配 (交叉情况)string test4="{ [(]) }";cout<<"测试 4: "<<test4<<endl;MatchBrackets(test4);cout<<endl;// 左括号多余string test5="((( [{}]";cout<<"测试 5: "<<test5<<endl;MatchBrackets(test5);cout<<endl;return0;}

使用STL 中的std::stack来解题

本文给出两道题目来进行应用:

后缀表达式的计算:

  • 题目说明:计算后缀表达式的值
  • ps:该题目在算法分享02——调度场算法一文中有所提及,但只给出核心思路,并未给出示例代码,下面本文仔细说明:
  • 核心思路:过程非常简单直接,按部就班地做就可实现
    1.左起依次读取表达式的一个符号
    2.若读入的是操作数,则将其压入栈中
    3.若读入的是运算符,则从栈中连续弹出两个元素,进行相应的运算,并将结果压入栈中
    4.若读入的是结束符,则栈顶元素是计算结果
  • 题目来源:洛谷 P1449 后缀表达式
    • 特别说明:@为表达式的结束符号;.为操作数的结束符号。
  • 示例代码(这两种方法实在代码书写的思路过程上有所不同,但在进行的核心操作上面依旧一样)
    1. 方法一:一层for循环,内嵌判断来实现
#include<iostream>#include<string>#include<stack>#include<cctype>usingnamespacestd;intmain(){string hz;cin>>hz;stack<int>ret;for(inti=0,num=0;hz[i]!='@';i++){if(isdigit(hz[i])){num=num*10+(hz[i]-'0');if(!isdigit(hz[i+1])){ret.push(num);num=0;}}elseif(hz[i]!='.'){inta=ret.top();ret.pop();intb=ret.top();ret.pop();if(hz[i]=='+')ret.push(a+b);elseif(hz[i]=='-')ret.push(b-a);elseif(hz[i]=='*')ret.push(a*b);elseif(hz[i]=='/')ret.push(b/a);}}cout<<ret.top()<<endl;return0;}
  1. 方法二:两层for循环,第一层for循环负责处理每个操作数和运算符,第二层的while循环负责处理连续的数字字符来构成一个完整的操作数,并处理连续的运算符来进行计算
#include<iostream>#include<string>#include<stack>#include<cctype>usingnamespacestd;intmain(){string hz;cin>>hz;stack<int>ret;for(inti=0;hz[i]!='@';i++){intnum=0;while(isdigit(hz[i])){num=num*10+(hz[i]-'0');i++;}ret.push(num);while(!isdigit(hz[i+1])&&hz[i+1]!='@'){i++;inta=ret.top();ret.pop();intb=ret.top();ret.pop();if(hz[i]=='+')ret.push(a+b);elseif(hz[i]=='-')ret.push(b-a);elseif(hz[i]=='*')ret.push(a*b);elseif(hz[i]=='/')ret.push(b/a);}}cout<<ret.top()<<endl;return0;}

中缀表达式的计算:

  • 题目说明:计算中缀表达式的值
  • 核心思路:(使用两个栈来实现):
    1. 遇到数字,直接入运算数栈
    2. 遇到运算符,比较优先级:
      1. 如果当前运算符优先级高于栈顶运算符,直接入运算符栈
      2. 否则,循环弹出运算符栈顶的运算符,并从运算数栈弹出两个数进行计算,直到当前运算符优先级高于栈顶运算符或栈空,然后将当前运算符入栈
    3. 遇到左括号,直接入运算符栈
    4. 遇到右括号,循环弹出运算符栈顶的运算符,并从运算数栈弹出两个数进行计算,直到遇到左括号为止,此时将左括号弹出但不参与计算
  • 参考题目:洛谷 P10079 EX 中缀表达式
    • 说明:此题更加难,还涉及到幂运算以及表达式合法的判断,目前就用更为简单的实现来说明栈的应用,因此下面只给出含加减乘除的中缀表达式的计算,且默认表达式合法。在后续讲述栈的的进阶等内容时再仔细分析~
  • 示例代码:
#include<iostream>#include<stack>#include<string>usingnamespacestd;// 两个栈直接设置为全局的stack<int>n;// 运算数栈stack<char>op;// 运算符栈// 判断符号优先级的函数intpriority(charc){if(c=='*'||c=='/')return2;if(c=='+'||c=='-')return1;return0;}// 进行具体运算的函数voidcal(){intb=n.top();n.pop();inta=n.top();n.pop();chars=op.top();op.pop();if(s=='+')n.push(a+b);elseif(s=='-')n.push(a-b);elseif(s=='*')n.push(a*b);elseif(s=='/')n.push(a/b);}intmain(){string mz;cin>>mz;for(inti=0;i<mz.length();i++){if(isdigit(mz[i])){n.push(mz[i]-'0');}else{if(op.empty()){op.push(mz[i]);}elseif(mz[i]=='('||priority(mz[i])>priority(op.top())){op.push(mz[i]);}elseif(mz[i]==')'){while(op.top()!='('){cal();}op.pop();}else{while(!op.empty()&&priority(op.top())>=priority(mz[i])){cal();}op.push(mz[i]);}}}while(!op.empty()){cal();}cout<<n.top()<<endl;return0;}

总结

以上就介绍了栈应用的三个例题,基本全面地熟悉了栈的特性与操作,在对这些例题的熟悉掌握之后,还可对列出的参考题目题目来源中的题再进行深入思考

加油,数据结构的实战我们已经迈上了脚踏实地的第一步!~

http://www.jsqmd.com/news/634904/

相关文章:

  • 共话电池弹片制造商哪家技术强,优质品牌推荐与选购攻略 - mypinpai
  • 如何高效使用开源业务平台Ever Gauzy:完整实战教程
  • 从‘帕金森’到‘稳如狗’:我的平衡小车PID调参实战心路历程
  • 2026去咖啡渍美白牙膏选购:成分党教你选,温和去渍美白清新 - 资讯焦点
  • Starward游戏启动器架构深度解析:多游戏统一管理解决方案实战指南
  • 手把手带你入门虚拟机:概念、软件对比、安装与网络配置全解析
  • 2026 快闪店全自动商用咖啡机推荐:出杯快、扛得住、清洗不费劲 - 品牌2026
  • Godot资源解包终极指南:快速提取PCK文件的完整教程
  • 终极Dell G15散热控制架构揭秘:WMI逆向工程与高性能替代方案深度解析
  • LED 高反射率白胶在Mini/Micro LED封装中的关键作用与优化策略
  • Windows环境下DataEase一站式安装指南(含WSL2+Docker配置)
  • 如何快速上手TermKit:10分钟安装与配置完整指南
  • 终极跨平台模组下载神器:WorkshopDL完整高效使用指南
  • 显卡要求高吗?实测Asian Beauty Z-Image Turbo在不同配置下的运行表现
  • Xposed钉钉助手:5分钟完成位置模拟的完整指南
  • 安徽消毒剂洗衣液哪里生产? - 中媒介
  • GLiNER与spaCy集成教程:打造企业级NLP流水线的完整方案
  • EFLNet实战解析:自适应损失与动态头在红外小目标检测中的协同优化
  • 武汉婚介公司的多元化演进:从传统牵线到全周期服务 - 品牌评测官
  • Dell G15散热控制终极方案:开源Thermal Control Center深度技术解析
  • 终极GET3D性能优化指南:7个实用技巧大幅减少GPU内存占用并提升生成速度
  • 2026年雪梨榨汁机厂家推荐:螺旋榨汁机/中草药榨汁机/大型工业榨汁机专业供应 - 品牌推荐官
  • PyCharm提交项目代码到GitHub与Gitee的方法,日常记录,自己用版本
  • 项目实训小组博客(一):项目开发规划
  • Jenkins自动化部署:如何安全存储和使用npm的authToken(附最佳实践)
  • BiliTools哔哩哔哩工具箱:2026年最实用的跨平台B站资源管理解决方案
  • 美团礼品卡回收新手操作教程(2026年最新版) - 京顺回收
  • NotoCJK:为Android设备解锁完整中文字体体验的终极解决方案
  • TriliumNext终极同步指南:打造无缝跨设备知识管理体验
  • RexUniNLU代码实例:对接Milvus向量库,实现Schema语义相似度检索与推荐