考研数据结构2 | 使用 C++ 实现顺序栈 | 栈的基本应用之计算后缀表达式

2023-05-16

文章目录

  • 1、顺序栈 简介
  • 2、顺序栈 代码实现
  • 3、栈的应用之计算后缀表达式
    • 3.1 表达式介绍
    • 3.2 计算后缀表达式的实现
    • 3.3 完整代码
    • 3.4 LeetCode 提交代码

1、顺序栈 简介

在上一次的学习中,使用指针实现了链栈 使用 C++ 实现链栈,接下来学一下顺序栈的实现。

回顾一下栈的概念:

栈是只允许在一端(即栈顶)进行插入或删除操作的线性表,属于逻辑结构。

回顾一下栈的数学性质:

n 个不同元素进栈,出栈元素不同排列的个数为 Catalan (卡特兰)数,即 1 n + 1 C 2 n n \frac{1}{n+1}C^{n}_{2n} n+11C2nn

顺序栈是通过顺序表实现的,是用一组 地址连续 的存储单元依次存储数据元素,简单理解就是用数组来存储的。

顺序栈和顺序表共同的特点为:逻辑上相邻的元素在物理位置上也相邻,即逻辑顺序和物理顺序相同。

2、顺序栈 代码实现


接下来是一个最简单的顺序栈的代码实现

#define MaxSize 10004
// 不带头结点的顺序栈
typedef struct {
    int data[MaxSize];
    int top;
}SeqStack;
// 创建顺序栈
SeqStack createStack(){
    SeqStack S;
    S.top = -1;
    return S;
}
// 判断栈是否为空
bool StackEmpty(SeqStack S){
    return S.top == -1;
}
// 入栈
bool Push(SeqStack &S, int x){
    if(S.top == MaxSize - 1) {    // 栈满报错
        return false;
    } else {
        S.data[++S.top] = x;
        return true;
    }
}
// 出栈
bool Pop(SeqStack &S, int &x){
    if(StackEmpty(S)) {
        return false;           // 当为空栈时直接返回
    } else {
        x = S.data[S.top--];
        return true;
    }
}

3、栈的应用之计算后缀表达式


接下来我们通过一个题目 剑指 Offer II 036. 后缀表达式 来验证自己实现的顺序栈的正确性。

3.1 表达式介绍

在做提前我们有必要了解一下后缀表达式,相应的还有前缀、中缀表达式。

  • 中缀表达式

中缀表达式是一个通用的算术或逻辑公式表示方法,我们平时用的就是中缀表达式,例如,(1+1) * 2,结果为4,这种表达式可以轻松用肉眼计算。
特点:除了括号限制运算优先性以外,运算符左右都为运算数

  • 前缀表达式

前缀表达式又称波兰表达式,是由一位波兰的数学家提出的,用于简化命题逻辑的一种表达式表示方式。例如 (1+1) * 2 的中缀转为前缀表达式为:* + 1 1 2
特点:不含括号就能表示运算优先性,运算符在两个运算数的前面

  • 后缀表达式

后缀表达式又称逆波兰表达式,例如 (1+1) * 2 的中缀转为后缀表达式为:1 1 + 2 *
特点:不含括号就能表示运算优先性,运算符在两个运算数的后面

在考研考题中经常会考察使用栈来实现表达式的转换,这里主要了解后缀表达式。

记录一下中缀转为前缀和后缀的要点:

  • 中缀转后缀:

左优先原则:只要左边运算符能先计算,就优先计算左边的。

例: 1+(1*2*3),转为后缀为, 1 1 2 * 3 * +,这里注意到先计算的是 (1*2*3) ,不过是先计算1 * 2 ,即 1 2 * ,然后在将这个结果视为一个数继续与 * 3 进行计算。

  • 中缀转后缀:

右优先原则:只要右边的运算符能先计算就先计算右边的。

例: 1+(1*2*3),转为前缀为, + 1 * 1 * 2 3

3.2 计算后缀表达式的实现

后缀表达式特点:运算符在操作数的后面,于是当我们遇到运算符时,直接往前面找操作数进行运算即可。只需要用一个栈来存储操作数。

设存储操作数的栈为 S S S,栈含有基本操作函数: P u s h Push Push 入栈 , P o p Pop Pop 出栈

算法实现:

  1. 遇到操作数(0-9)时,一直往后扫描, P u s h Push Push当前的操作数
  2. 遇到操作符 + 、 − 、 ∗ 、 / +、-、*、/ +/ (设为o)时, b = P o p ( ) , a = P o p ( ) b = Pop() , a = Pop () b=Pop()a=Pop() 。计算 a o b 的结果,并 P u s h Push Push
  3. 遍历完后缀表达式后, P o p ( ) Pop() Pop() 即为最终运算的结果

注意点:

  • 当后缀表达式为一维字符数组时,需注意表达式的遍历,当遇到空格直接跳过,当遇到负号时需特殊判断,负号有可能是运算符也有可能是操作数里的负号。
  • 在出栈的时候,首先出栈的是后出现的元素 b,其次出现的才是之前的元素 a, 这个顺序不能颠倒,否则在进行减法和乘法运算时结果就会出错。
  • 创建栈时候需注意栈的容量,最大容量根据题目给的范围来定。

3.3 完整代码

在提交代码到 剑指 Offer II 036. 后缀表达式 前,先写一下完整的代码,包括输入输出。

//
// Created by uni1024 on 2022/10/8.
//
#include <cstdlib>
#include <iostream>
#define MaxSize 10004
// 不带头结点的顺序栈
typedef struct {
    int data[MaxSize];
    int top;
}SeqStack;
// 创建顺序栈
SeqStack createStack(){
    SeqStack S;
    S.top = -1;
    return S;
}
// 判断栈是否为空
bool StackEmpty(SeqStack S){
    return S.top == -1;
}
// 入栈
bool Push(SeqStack &S, int x){
    if(S.top == MaxSize - 1) {    // 栈满报错
        return false;
    } else {
        S.data[++S.top] = x;
        return true;
    }
}
// 出栈
bool Pop(SeqStack &S, int &x){
    if(StackEmpty(S)) {
        return false;           // 当为空栈时直接返回
    } else {
        x = S.data[S.top--];
        return true;
    }
}
// 辅助函数, 判断字符串s的第i个元素是否为数字
bool isDigit(char *s, int i){
    return s[i] >= '0' && s[i] <= '9';
}
// 辅助函数, 将数字字符串转为数字, 直到遇到空格
bool getNum(char *s, int &i, int &x){
    if(isDigit(s,i)){                   // 若当前字符为数字则开始运算
        // 判断数字的正负
        int flag;
        if(i >= 1 && s[i-1] == '-')
            flag = -1;
        else
            flag = 1;
        int num = s[i++] - '0';
        while(isDigit(s, i)){          // 记录连续的数字
            num = num * 10 + s[i++] - '0';
        }
        x = num * flag;             // 记录最终结果
        return true;
    }
    else return false;
}
int main(){
    printf("开始程序,请输入一个标准的后缀表达式(用空格隔开):\n");
    char s[MaxSize * 10];
    gets(s);
    printf("获取到的后缀表达式为:%s\n", s);
    // 核心算法

    SeqStack  S = createStack();     // 初始化栈
    int i = 0;      // 记录当前遍历的位置
    int x;          // 临时变量
    int a, b;       // 临时变量
    while(s[i] != '\0'){
        // 跳过空格字符
        if(s[i] == ' ') { i++ ; continue;}
        // 1. 当遇到数字时候直接入栈
        if(isDigit(s, i)){
            getNum(s, i, x);
            Push(S, x);
        } else {
            // 跳过数字负号的情况(因计算数字时会判断正负性)
            if(s[i] == '-' && isDigit(s, i+1)) {
                i++;
                continue;
            }
            // 其他情况
            if(Pop(S, b) && Pop(S, a)){
                // 计算后继续入栈
                switch (s[i]) {
                    case '+': Push(S, a + b);break;
                    case '-': Push(S, a - b); break;
                    case '*': Push(S, a * b); break;
                    case '/': Push(S, a / b); break;
                    default : break;
                }
            }
        }
        i ++ ;  // 继续遍历下一个字符
    }
    Pop(S, x);
    printf("运算结果: %d\n",x);
    return 0;
}

测试数据与结果:

开始程序,请输入一个标准的后缀表达式(用空格隔开):
4 13 5 / +
获取到的后缀表达式为:4 13 5 / +
运算结果: 6

3.4 LeetCode 提交代码


剑指 Offer II 036. 后缀表达式

由于C语言不支持 bool 类型以及 函数中使用&引用参数的地址,这里则提交的是 C++的代码,这里用到了 C++ 的 vector 的遍历,通过使用 for(auto 循环变量:Vector容器变量) 的方式,了解即可。其中辅助函数与之前写的稍有不同,因为这个题目给的输入数据是二维的,相对来说难度就小了一些。

#include <cstdlib>
#include <iostream>
#define MaxSize 10004
// 不带头结点的顺序栈
typedef struct {
    int data[MaxSize];
    int top;
}SeqStack;
// 创建顺序栈
SeqStack createStack(){
    SeqStack S;
    S.top = -1;
    return S;
}
// 判断栈是否为空
bool StackEmpty(SeqStack S){
    return S.top == -1;
}
// 入栈
bool Push(SeqStack &S, int x){
    if(S.top == MaxSize - 1) {    // 栈满报错
        return false;
    } else {
        S.data[++S.top] = x;
        return true;
    }
}
// 出栈
bool Pop(SeqStack &S, int &x){
    if(StackEmpty(S)) {
        return false;           // 当为空栈时直接返回
    } else {
        x = S.data[S.top--];
        return true;
    }
}
// 辅助函数, 判断字符串s的第i个元素是否为数字
bool isDigit(string s, int i){
    return s[i] >= '0' && s[i] <= '9';
}
// 辅助函数, 将数字字符串转为数字, 直到遇到空格
int getNum(string s){
    int i = 0;
    int flag = 1;      // 判断数字的正负
    if(s[0] == '-') { flag = -1; i = 1; }
    int num = s[i++] - '0';
    while(s[i] != '\0' && isDigit(s, i)){          // 记录连续的数字
        num = num * 10 + (s[i++] - '0');
  }
   return num * flag;
}

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
     SeqStack S = createStack();     // 初始化栈
    int x;          // 临时变量
    int a, b;       // 临时变量
    // 遍历字符串
    for(auto s : tokens){		
        if(isDigit(s, 0) || isDigit(s, 1)){ // 情况1: 操作数
            Push(S, getNum(s));
        } else {    						// 情况2: 运算符
            char ch = s[0];
            if(Pop(S, b) && Pop(S, a)){
                // 计算后继续入栈
                switch (ch) {
                    case '+': Push(S, a + b); break;
                    case '-': Push(S, a - b); break;
                    case '*': Push(S, a * b); break;
                    case '/': Push(S, a / b); break;
                    default : break;
                }
            }
        }  
    }
    // 取出最终结果
    Pop(S, x);
    return x;    
    }
};

提交结果:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

考研数据结构2 | 使用 C++ 实现顺序栈 | 栈的基本应用之计算后缀表达式 的相关文章

  • 高仿萌聚 app ,内容简直是宅男福利啊

    mengqu 项目地址 xff1a panacena mengqu 简介 xff1a 高仿萌聚 app xff0c 内容简直是宅男福利啊 xff01 高仿萌趣 app 最近下了个叫做 萌趣 的 app xff0c 内容简直是宅男福利啊 xf
  • 人脸识别扫描(活体检测功能,眨眼、摇头、点头),身份证认证

    FaceAC 项目地址 xff1a sxpl FaceAC 简介 xff1a 人脸识别扫描 xff08 活体检测功能 xff0c 眨眼 摇头 点头 xff09 xff0c 身份证认证 更多 xff1a 作者 提 Bug 标签 xff1a 人
  • 全开源即时通讯(IM)系统 高仿微信

    android chat 项目地址 xff1a wildfirechat android chat 简介 xff1a 全开源即时通讯 IM 系统 高仿微信 更多 xff1a 作者 提 Bug 官网 标签 xff1a 野火 IM 是一套跨平台
  • OpenCV与机器视觉

    最近在网易云课堂把南科大于仕琪团队的OpenCV教程完整看了一遍 xff0c 对图像处理或者机器视觉又有了一个系统性的理解 OpenCV中文网站就是他创建的 xff0c 他的研究团队及其相应成果可以在个人网站中查阅 回想过去在图像处理方面的
  • Virtual Box+Ubuntu20.04+ROS2 Foxy配置

    ROS从最早的正式版本Box Turtle到现在也十几年了 而ROS2出来也挺久了 xff0c 一直没机会看看 好久也没弄ROS xff0c 这几天捣鼓了捣鼓 目录 1 Virtual Box安装Ubuntu20 04 2 ROS2 Fox
  • TI CC265x的IIC通讯读取IMU BMI08x数据

    SmartLink CC265x是TI公司出的无线MCU平台器件 最近玩了个小项目用TI的CC265x平板IIC接口通讯 xff0c 获取博世BMI08x陀螺仪 加速度计传感器的数据 本篇博客亦是对博客 树莓派IIC通讯获取BMI08x I
  • 三种方法在ROS中加载Qt库进行GUI设计

    编写ros程序 xff0c 因为有时会涉及到界面设计 xff0c 所以本人主要用的QtCreator IDE 首先当然是安装QtCreator xff0c 这个网上有很多安装教程和下载资源 xff0c 非常简单 由于Qt的工程大多采用qma
  • 在ROS中处理yaml文件

    ROS中的参数服务器 xff08 Parameter Server xff09 的相关操作可参见roscpp tutorials Tutorials Parameters 如果想要载入参数 xff0c 可以通过编写yaml文件 xff0c
  • ROS动态调参(dynamic reconfigure)客户端服务端之C++ Python实现

    在ROS系统中 xff0c 我们需要实时修改参数 xff0c 并能马上看到运行效果 这一功能是通过ros dynamic reconfigure包实现的 官网教程如下 xff1a dynamic reconfigure Tutorials
  • ROS中slam_gmapping、map_server源码解读及其librviz的使用

    SLAM全称simultaneous localization and mapping xff0c 即实时定位与地图构建 也就是说导航离不开地图 xff0c 目前常用的地图构建方法有三种 xff1a 1 gmapping xff0c 一种基
  • 记 - PC视频播放最强画质教程(Potplayer + madVR)

    PC视频播放最强画质教程 前言 xff1a 本次使用到的软件 工具 Potplayer播放器 Potplayer是目前我用到的最好用的宝藏视频播放软件 xff1a 内存占用低 无广告 支持视频格式多 功能强大 扩展性高 界面唯美 xff08
  • 【三维深度学习】多视角立体视觉 MVSNet代码解读

    MVSNet通过将相机几何参数编码到网络中 xff0c 实现了端到端的多视角三维重建 xff0c 并在性能和视觉效果上超越了先前算法 xff0c 并在eccv2018 oral中发表 模型主要包含四个主要步骤 xff1a 图像特征抽取 多视
  • 【pandas】删除满足条件元素所在的行

    在数据清洗时 xff0c 需要按照一定条件删除某些数据样本 xff0c 利用布尔表达式 索引和drop方法可以实现 1 pandas drop df 61 df drop df lt some boolean condition gt in
  • 【AI视野·今日Robot 机器人论文速览 第八期】Wed, 16 Jun 2021

    AI视野 今日CS Robotics 机器人学论文速览 Wed 16 Jun 2021 Totally 13 papers x1f449 上期速览 更多精彩请移步主页 Daily Robotics Papers Constrained Mo
  • 【CVPR2022】论文列表与下载——PartTwo

    CVPR2022将于6月22日召开 x1f389 x1f389 x1f389 xff0c 本次会议共收录了2067篇论文 由于数量较多 xff0c 本文将分四个子文章呈现 xff0c 可直接点击论文标题获取文档 x1f4c3 第一部分 x1
  • 【CVPR2022】论文列表与下载——PartThree

    CVPR2022将于6月22日召开 x1f389 x1f389 x1f389 xff0c 本次会议共收录了2067篇论文 由于数量较多 xff0c 本文将分四个子文章呈现 xff0c 可直接点击论文标题获取文档 x1f4c3 第一部分 x1
  • 【CVPR2022】论文列表与下载——PartFour

    CVPR2022将于6月22日召开 x1f389 x1f389 x1f389 xff0c 本次会议共收录了2067篇论文 由于数量较多 xff0c 本文将分四个子文章呈现 xff0c 可直接点击论文标题获取文档 x1f4c3 第一部分 x1
  • Python三维绘图--Matplotlib

    Python三维绘图 在遇到三维数据时 xff0c 三维图像能给我们对数据带来更加深入地理解 python的matplotlib库就包含了丰富的三维绘图工具 1 创建三维坐标轴对象Axes3D 创建Axes3D主要有两种方式 xff0c 一
  • 【深度学习】三维点云数据集总结

    点云数据集总结 三维点云数据 xff0c 三维深度学习 1 ShapeNet ShapeNet是一个丰富标注的大规模点云数据集 xff0c 其中包含了55中常见的物品类别和513000个三维模型 2 ShapeNetSem 这是一个小的数据
  • git push代码到远程新分支

    Git push 获取远程代码修改后 想要push到远端与原来不同的新分支 xff0c 可以使用下面的命令实现 xff1a git push origin 本地分支 远端希望创建的分支 例如git下来的分支为master span clas

随机推荐

  • 【numpy求和】numpy.sum()求和

    numpy sum a axis 61 None dtype 61 None out 61 None keepdims 61 initial 61 source 用于计算array元素的和 python中常用的numpy进行数学计算 xff
  • Nuttx romfs与启动脚本rcS

    ARM系统上电后 xff0c 系统将flash地址映射到零地址处 xff0c 处理器从零地址处开始运行第一条指令 而在零地址处 xff0c 一般是系统复位中断向量 xff0c 此处存放的是一条跳转指指令 xff0c 通过该条换指令 xff0
  • 在终端/命令行下打开文件浏览器窗口--Win cmd &Ubuntu terminal

    在命令行下想要可视化查看文件 xff0c 可以使用命令直接打开图形化窗口 1 Windows windows上可以使用explorer exe打开资源管理器 xff1a explorer exe span class token keywo
  • 127.0.0.0与0.0.0.0的区别

    1 IP地址分类 ref https tools ietf org html rfc1700 page 3 IP地址表示 IP地址由两个部分组成 xff0c net id和host id xff0c 即网络号和主机号 net id 表示ip
  • 【python】代码换行的几种方法

    代码太长怎么办 xff0c 反斜杠 引号 34 34 34 39 来帮忙 xff01 在写list或者较长的字符串时候 xff0c 或者多个循环造成IDE不够用时 xff0c 就需要代码换行了 主要的代码换行有通用的反斜杠 和针对字符串起作
  • 自己动手写C++迭代器

    综述 关于STL iterator和 iterator adapter 的部分我已在先前的博客 stl源码剖析笔记之iterator 中有所提及 xff0c 下面我们可以试着自己动手写一个简单的迭代器工具 step iterator xff
  • 【STM32F0】Keil 查看局部变量显示<not in scope>

    现象 xff1a 在进行STM32F0开发的时候出现了 调试代码 xff0c 添加变量Watch时 xff0c 显示not in scope 处理方式 xff1a 因为代码开了优化的处理 xff0c 把优化改到Level0 就可以解决问题
  • error: undefined reference to '__dso_handle'解决方案

    error undefined reference to 39 dso handle 39 解决方案 home NDK android ndk r9 sources cxx stl gnu libstdc 43 43 4 7 libs ar
  • ARM里的大端格式和小端格式分别是什么意思?

    当前的存储器 xff0c 多以byte为访问的最小单元 xff0c 当一个逻辑上的地址必须分割为物理上的若干单元时就存在了先放谁后放谁的问题 于是端 endian 的问题应运而生了 对于不同的存储方法 就有大端 big endian 和小端
  • STM32串口通信(基于缓冲区)编程及遇到的问题总结

    在写串口通信前阅读了STM32中文参考手册 xff0c 然后满心澎湃地写代码 在这个过程中遇一些让人郁闷的事情 xff0c 目前这些问题目前已经解决了 xff08 嘿嘿嘿 xff09 xff0c 特此来总结一番 串口的使用步骤大概如下 xf
  • 主板串口FIFO大小设置

    FIFO大小和芯片 驱动有关系 xff0c 可以在设备管理器里面调整大小 1 进入设备管理器 xff0c 右键选择串口属性 2 在端口设置里面选择高级 3 可以单独设定每一个串口的接收和发送区大小
  • mac终端 python scrapy爬虫 zsh: no matches found

    在学习Python爬虫时 xff0c 进行到scrapy板块 xff0c 执行genspider命令 输入scrapy genspider tongcheng https bj 58 com sou key 61 E5 89 8D E7 A
  • JSESSIONID的简单说明

    1 第一次访问服务器的时候 xff0c 会在响应头里面看到Set Cookie信息 只有在首次访问服务器的时候才会在响应头中出现该信息 上面的图JSESSIONID 61 ghco9xdnaco31gmafukxchph Path 61 a
  • 史上最全的常用开发工具类收集(持续更新中)

    外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img BtY85pbk 1577412535564 https img shields io badge QQ群 523167548 20 ff69b4 svg API
  • MFC学习之vc通过HTTP请求:Get或Post方式获取JSON信息(亲测可用)

    前段时间公司项目需要跟上一级平台对接一些采集回来的数据 xff0c 通过HTTP xff0c post方法上传JSON信息到指定的接口地址 本来呢 xff1f 我在入职时是面试的售后岗 xff0c 一家小公司 xff0c 当时公司软件方面一
  • mac安装虚拟机VMware fusion12 和ubantu系统

    一 基本安装 下载虚拟机VMware fusion12 我选择了不更新新版本并且允许访问辅助功能 选择 新建 接下来选择 从光盘或者映像安装 从下载目录把ubantu系统拖拽过去 点击安装完成 xff0c 将ubantu系统保存在虚拟机上即
  • VSCode常用命令---记录自己的常用命令

    一 nvm相关命令 node版本管理 查看已安装的版本 nvm list 使用版本 nvm use 版本号 安装版本 nvm install 版本号 卸载版本 nvm uninstall 版本号 常用命令 全局包安装 多用于gitee下载后
  • Ubuntu18.04 Realsense D435i驱动安装与配置

    InterRealSenseD435i SDK安装 一 命令行的安装方式安装 1 注册服务器的公钥 xff1a 打开终端输入 sudo apt key adv keyserver keys gnupg net recv key C8B3A5
  • Qt上位机:与STM32串口通信,数据收发,按钮控制LED

    Qt学习了几周 xff0c 做一个串口助手巩固一下最近学习的内容 遇到的问题1 xff1a write函数只能发送一次数据 xff0c 想要继续发送必须重新关闭打开串口 xff0c 每次只能发送一次数据 解决办法 xff1a 在网上找不到类
  • 考研数据结构2 | 使用 C++ 实现顺序栈 | 栈的基本应用之计算后缀表达式

    文章目录 1 顺序栈 简介2 顺序栈 代码实现3 栈的应用之计算后缀表达式3 1 表达式介绍3 2 计算后缀表达式的实现3 3 完整代码3 4 LeetCode 提交代码 1 顺序栈 简介 在上一次的学习中 xff0c 使用指针实现了链栈