堆栈应用:表达式求值(C语言)

2023-05-16

文章目录

  • 堆栈应用:表达式求值(C语言)
    • 两个定义
    • 大致过程
    • 具体代码

堆栈应用:表达式求值(C语言)

两个定义

  • 中缀表达式:运算符号位于两个运算数之间。如:a + b * c - d / e
  • 后缀表达式:运算符号位于两个运算数之后。如:a b c * + d e / -

大致过程

  1. 用后缀表达式求值:
    对于后缀表达式,可以比较容易处理。大致过程为:将后缀表达式从左到右扫描,遇到数字就将数字压如堆栈中,遇到运算符就将运算符前面的两个数字出栈,将运算符置于两数字之间运算,将运算结果入栈。最后栈中剩余的最后一个元素就是运算结果。

    • 例子】求:6 2 / 3 - 4 2 * +

      步骤

      1. 从左到右扫描,遇到6和2,分别将其压进堆栈中。
      2. 遇到除号,将6和2出栈,计算6/2=3,将3入栈;继续扫描,后面遇见一个3,继续入栈。
        在这里插入图片描述
      3. 遇到减号,将两个3出栈,计算3-3=0,将0入栈;继续扫描,后面遇见4与2,将其入栈。
        在这里插入图片描述
      4. 遇到乘号,将4和2出栈,计算4*2=8,将8入栈;
        在这里插入图片描述
      5. 遇到加号,将0和8出栈,计算0+8=8,将8入栈,扫描之后发现已经没有字符,而堆栈中只有8这个元素,故结果为8。
        在这里插入图片描述
  2. 将中缀表达式转换为后缀表达式
    所以现在我们要做的就是将中缀表达式变成后缀表达式。观察两种表达式的转换:2 + 9 / 3 - / 5 —> 2 9 3 / + 5 -

    1. 运算数相对顺序不变
    2. 运算符号顺序发生改变
      • 需要存储“等待中”得运算符号
      • 要将当前运算符号与“等待中”的运算符号比较

    中缀表达式转换为后缀表达式的过程

    • 从头到尾读取中缀表达式的每个对象,对不同的对象按照不同的情况处理。

      1. 运算符:直接输出;
      2. 左括号:压入堆栈;
      3. 右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出);
      4. 运算符:
        • 若优先级大于栈顶运算符时,则把它压入栈中;
        • 若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;在比较新的栈顶元素运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压入栈中。
      5. 若各对象处理完毕,则将堆栈中存留的运算符一并输出。

      在这里插入图片描述

具体代码

  1. main.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    int main(void)
    {
        char InfixStr[MAXSIZE] = { 0 }, SuffixStr[MAXSIZE] = { 0 };
        Read_Expression(InfixStr,MAXSIZE);//将在键盘上输入的中缀表达式保存在字符串InfixStr中
        //puts(InfixStr);
        InfixToSuffix(InfixStr, SuffixStr,MAXSIZE);//将中缀表达式抓换成后缀表达式
        //puts(SuffixStr);
        printf("\n结果是:%f\n", Calculate(SuffixStr, MAXSIZE));
    
        system("pause");
        return 0;
    }
    
  2. Expression_evaluation.h

    #define MAXSIZE 100
    
    //存放字符的堆栈
    struct SNode {
        char Data[MAXSIZE];
        int Top;
    };
    typedef struct SNode* Stack;
    
    //存放浮点数的堆栈
    struct SNodeOfInt {
        float Data[MAXSIZE];
        int Top;
    };
    typedef struct SNodeOfInt* StackOfFloat;
    
    int Compare(char, Stack);//在中后缀表达式转换的时候,加减乘除号比较优先级,判断加减乘除号是否入栈
    void Read_Expression(char[], int);//读取键盘输入的表达式
    void InfixToSuffix(char[], char[], int);//将中缀表达式转换为后缀表达式
    float Calculate(char[], int);//由后缀表达式求出表达式结果
    
    //入栈
    void Push(Stack, char);
    void PushFloat(StackOfFloat, float);
    
    //出栈
    char Pop(Stack);
    float PopFloat(StackOfFloat);
    
  3. Read_Expression.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    
    void Read_Expression(char str[], int length)
    {
        printf("请输入所需求值的中缀表达式(英文输入法):\n");
        gets(str);
    
        return str;
    }
    
  4. InfixToSuffix.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    void InfixToSuffix(char Infix[], char Suffix[], int length)
    {
        int i = 0,j=0,Tag=0;
        //建立一个空栈
        struct SNode S_1 = { {'\0'},-1 };
        Stack SPtr = &S_1;
    
        //扫描中缀表达式的所有字符,根据字符的值做出不同操作
        while (Infix[i] != '\0')
        {
            //当扫描到数字的时候,直接输出到字符串Suffix中
            if (Infix[i] <= '9'&&Infix[i] >= '0')
            {
                Suffix[j] = Infix[i];
                j++;
            }
            //当扫描到空格的时候,直接输出到字符串Suffix中
            else if (Infix[i] == ' ')
            {
                Suffix[j] = Infix[i];
                j++;
            }
            //当扫描到加减乘除运算符的时候,将其与堆栈顶元素比较优先级,根据优先级决定进栈还是栈顶元素出栈输出
            else if (Infix[i] == '+' || Infix[i] == '-' || Infix[i] == '*' || Infix[i] == '/')
            {
                Suffix[j] =' ';
                j++;
                //当栈顶元素出栈输出时,扫描到的元素要继续与新的栈顶元素比较优先级,直至扫描到的元素入栈
                Tag = 0;
                while (Tag == 0)
                {
                    Tag = Compare(Infix[i], SPtr);
                    if (Tag == 0)
                    {
                        Suffix[j] = Pop(SPtr);
                        j++;
                    }
                    else
                    {
                        Push(SPtr, Infix[i]);
                    }
                }
            }
            //如果扫描到左括号,直接进栈
            else if(Infix[i]=='(')
            {
                Push(SPtr, Infix[i]);
            }
            //如果扫描到右括号,一直出栈输出直到栈顶元素是左括号,然后将栈顶的左括号出栈但不输出
            else if (Infix[i] == ')')
            {
                Suffix[j] = ' ';
                j++;
                while (SPtr->Data[SPtr->Top] != '(')
                {
                    Suffix[j] = Pop(SPtr);
                    j++;
                }
                Pop(SPtr);
            }
            i++;
        }
        //扫描完之后将堆栈中所有元素出栈
        while (SPtr->Top != -1)
        {
            Suffix[j] = Pop(SPtr);
            j++;
        }
    }
    
  5. Compare.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    int Compare(char ch_1, Stack SPtr)
    {
        //如果堆栈空,将扫描到的运算符号进栈
        if (SPtr->Top == -1)
        {
            return 1;
        }
        //当栈顶是左括号时,将扫描到的运算符号进栈
        if (SPtr->Data[SPtr->Top] == '(')
        {
            return 1;
        }
        //当栈顶是乘号或者除号的情况
        else if (SPtr->Data[SPtr->Top] == '/' || SPtr->Data[SPtr->Top] == '*')
        {
            //如果扫描到的也是乘号或除号,将栈顶元素出栈
            if (ch_1 == '*' || ch_1 == '/')
            {
                return 0;
            }
            //如果扫描到的是加号或者减号,将栈顶元素出栈
            else
            {
                return 0;
            }
        }
        //当栈顶元素是加号或者减号时
        else
        {
            //如果扫描到的也是乘号或除号,将栈顶元素进栈
            if (ch_1 == '*' || ch_1 == '/')
            {
                return 1;
            }
            //如果扫描到的是加号或者减号,将栈顶元素出栈
            else
            {
                return 0;
            }
        }
    }
    
  6. Calculate.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    float Calculate(char Suffix[], int length)
    {
        float sum = 0, temp = 0, first = 0, last = 0;
        int i = 0;
        //建立一个空栈
        struct SNodeOfInt S = { {0},-1 };
        StackOfFloat SPtr = &S;
        while (Suffix[i] != '\0')
        {
            //扫描后缀表达式,计算结果
            while (Suffix[i] != '\0')
            {
                //当扫描到的是数字字符,将其转换成数字,并将其压入栈中
                if (Suffix[i] <= '9'&&Suffix[i] >= '0')
                {
                    sum = 0;
                    while (Suffix[i] <= '9'&&Suffix[i] >= '0')
                    {
                        temp = (float)(Suffix[i] - '0');
                        sum = sum * 10 + temp;
                        i++;
                    }
                    PushFloat(SPtr, sum);
                }
    
                //当扫描到空格,忽略
                if (Suffix[i] == ' ')
                {
                    i++;
                }
                //当扫描到加减乘除号,将栈顶两个元素弹出,并将其用扫描到的运算符号计算,将结果压入栈中
                if (Suffix[i] == '+' || Suffix[i] == '-' || Suffix[i] == '*' || Suffix[i] == '/')
                {
                    last = PopFloat(SPtr);
                    first = PopFloat(SPtr);
                    if (Suffix[i] == '+')
                    {
                        PushFloat(SPtr, first + last);
                        i++;
                    }
                    else if (Suffix[i] == '-')
                    {
                        PushFloat(SPtr, first - last);
                        i++;
                    }
                    else if (Suffix[i] == '*')
                    {
                        PushFloat(SPtr, first*last);
                        i++;
                    }
                    else
                    {
                        PushFloat(SPtr, first / last);
                        i++;
                    }
                }
    
            }
            return PopFloat(SPtr);//栈中最后一个数字就是结果,将其返回
        }
    
    }
    
  7. Pop.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    char Pop(Stack SPtr)
    {
        if (SPtr->Top == -1)
        {
            printf("堆栈空");
            return '\n';//栈空时返回回车键
        }
        else
        {
            return (SPtr->Data[(SPtr->Top)--]);//先返回栈顶元素,再将Top减一。
        }
    }
    
    float PopFloat(StackOfFloat SPtr)
    {
        if (SPtr->Top == -1)
        {
            printf("堆栈空");
            return '\n';//栈空时返回回车键
        }
        else
        {
            return (SPtr->Data[(SPtr->Top)--]);//先返回栈顶元素,再将Top减一。
        }
    }
    
  8. Push.c

    #include<stdio.h>
    #include<stdlib.h>
    #include"Expression_evaluation.h"
    
    void Push(Stack SPtr, char itme)
    {
        if (SPtr->Top == MAXSIZE - 1)
        {
            printf("堆栈满");
            return;
        }
        else
        {
            SPtr->Data[++(SPtr->Top)] = itme;//Top先自加一,然后再给栈顶元素赋值。
            return;
        }
    }
    
    void PushFloat(StackOfFloat SPtr, float itme)
    {
        if (SPtr->Top == MAXSIZE - 1)
        {
            printf("堆栈满");
            return;
        }
        else
        {
            SPtr->Data[++(SPtr->Top)] = itme;//Top先自加一,然后再给栈顶元素赋值。
            return;
        }
    }
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

堆栈应用:表达式求值(C语言) 的相关文章

  • Python --语法自纠

    文章目录 1 输入2 数据类型转换 xff0c 字符串3 字典 xff0c 列表 xff0c 元组4 语法0 错题 1 输入 输入eval作用一次输入一个或多个 map print format m n format输出 2 数据类型转换
  • 强化学习算法复现(六):DoubleDQN_gym倒立摆

    建立RL brain py span class token keyword import span torch span class token keyword import span torch span class token pun
  • Android的控件绑定----ViewBinding

    在Android开发中 xff0c 控件的绑定是开发者无法绕开的一道程序 是Android开发中最原始 xff0c 也是最基础的一种获取View的方法 在一个复杂布局的页面时 xff0c 我们要一个个控件去调用findViewById方法去
  • C++ OpenCV CV_***未声明的标识符的解决办法

    1 OpenCV cvtColor CV BGR2GRAY未声明的标识符的解决办法 加上这个引用即可 include lt opencv2 imgproc types c h gt 2 opencv里面CV FOURCC找不到标识符 CV
  • 多线程-生产者和消费者模式

    1 简单实现多线程 多线程是多任务处理的一种特殊形式 xff0c 多线程处理允许让一个进程中同时运行两个或两个以上的线程 这样的话 xff0c 能更加充分发挥计算机的性能 xff0c 并高效完成用户的任务 多线程实现的三步骤 xff1a 第
  • HTML网页注册图片

    lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt lt title gt lt style type 61 34 t
  • [WAX云钱包】解决Cloudflare通过SSL指纹识别实现的反爬虫机制

    WAX云钱包 在之前的多篇文章中 xff0c 我们使用 Python 43 Selenium 来实现WAX链游脚本 xff0c 主要是因为很多玩家一开始都是用WAX云钱包注册的账号 xff0c 而WAX云钱包的私钥托管在云端 xff0c 我
  • 小狼毫[rime_win][眀月拼音]简单配置方法

    小狼毫 rime win 朙月拼音 简单配置方法 我自己的配置文件 当配置后 需要重新部署后设置才能生效 需要修改的文件 需要修改 增加的文件均在用户文件夹下 用户文件夹可以通过右键输入法状态栏的图标后点击用户文件夹到达 修改 增加的文件名
  • 生产者消费者模式(c++)

    什么是生产者消费者模式 xff1f 想象一下 xff0c 你早上起来肚子快饿扁了 xff0c 去包子铺买包子 xff0c 包子铺有三个人在做包子 xff08 也可以是一个 xff09 xff0c 这些人就是生产者 xff0c 你作为买包子的
  • go语言interface转string、bool、int

    在go语言中interface转string可以直接使用fmt提供的fmt函数 xff0c 而转bool和int则是在string的基础上来进行转换 xff0c 详见如下代码 func Get f string value interfac
  • centos7中启动juoyter notebook后,复制链接无法打开网页

    centos7中启动juoyter notebook后 xff0c 复制链接无法打开网页 xff0c 一直停留在如下界面 xff1a 解决办法 xff1a 这需要在Linux浏览器中打开 在windows中无法打开 xff0c 若没有安装l
  • 数据结构——BF, KMP

    文章目录 1 串的基本操作2 串的BF模式 朴素的模式匹配 暴力匹配 定位操作 3 串的KMP模式匹配 定位操作 1 规则 xff1a 2 举例 xff1a 3 采用以空间换时间策略 xff0c 操作方法如下 xff1a 4 操作举例 xf
  • linux如何在界面和终端的不同模式下运行pyspark?

    一 xff0c 界面打开 1 直接输入jupyter notebook后打开界面 查看运行模式 xff1a 输入sc master 若输出为 xff1a local xff0c 则表示它是在本地模式下运行 2 xff0c 如何使用jupyt
  • 官网下载eclipse太慢解决办法及jdk版本要求

    1 Eclipse 4 6 Neon 需要JDK1 8版本 2 Eclipse 4 5 Mars 需要JDK1 7及以上版本 3 Eclipse 4 4 Luna 需要JDK1 7及以上版本 4 Eclipse 4 3 Kepler 需要J
  • Ubuntu中Pycharm快捷方式只能以sudo sh pycharm.sh运行,双击快捷方式没反应怎么办?

    创建pycharm快捷方式的博客文章很多 xff0c 我找了很久才解决我的问题 xff0c 这里主要参考这篇 xff1a 链接 link 主要问题 双击pycharm快捷方式没反应 xff0c 只能在终端中用sudo sh pycharm
  • Gazebo上帝视角里程计 get_model_state 绝对里程计

    Gazebo model states Gazebo有一个服务 gazebo get model state 和一个话题 gazebo model states 来反馈model的状态 服务 gazebo get model state 话
  • 【GaussDB数据库----连接】

    1 确认连接信息 客户端工具通过CN连接数据库 因此连接前 xff0c 需获取CN所在服务器的IP地址及CN的端口号信息 客户端工具可以通过任何一个CN连接数据库 以操作系统用户omm登录安装有MPPDB服务的任一主机 执行source B
  • 天干地支(出生年月的转换)

    十 天干 xff1a 甲 xff08 ji xff09 乙 xff08 y xff09 丙 xff08 b ng xff09 丁 xff08 d ng xff09 戊 xff08 w xff09 己 xff08 j xff09 庚 xff0
  • http转https后资源加载失败的解决方案

    之前没给域名加SSL证书的时候 xff0c 项目好好的 xff0c icon图标还有 xff0c 给域名了SSL证书后 xff0c icon图标就不在了 原因就是因为项目本身采用http的资源文件 xff0c 换成https后就不解析这些资
  • Docker 安装 Redis + Spring Boot 整合 Redis

    Docker安装Redis 一 启动docker容器 systemctl start docker 二 拉取redis镜像 docker pull redis 三 端口映射 docker run name redis p 6379 6379

随机推荐

  • 如何保证缓存与数据库数据一致性

    redis系列之数据库与缓存数据一致性解决方案 重点文章 xff1a https www cnblogs com cxxjohnson p 8519616 html 你只要用缓存 xff0c 就可能会涉及到缓存与数据库双存储双写 xff0c
  • 2020年:maven配置最新阿里云镜像,以及在IDEA中的设置

    记得当初学习Maven的时候 xff0c 由国外的中央仓库切换为阿里云镜像之后 xff0c 用起来是辣么地丝滑 不过最近一段时间 xff0c Maven却总是出现一些问题 xff0c 本地库里也总是出现一些 lastUpdated文件 xf
  • Node.js—— MySQL(第三方API ),web开发模式

    文章目录 0 目标1 数据库 xff08 数据库管理系统 xff09 2 MySQL3 SQL语句1 基本语句2 js 操作数据库中的查询 xff0c 增加 xff0c 更新 xff08 改 xff09 xff0c 删除 3 MYSQL操作
  • 实现生产者消费者模式的三种方式

    什么是生产者消费者模式 简单来说 xff0c 生产者消费者模式就是缓冲区 那么这么做有两个好处 xff0c 一个是解耦 xff0c 第二个是平衡生产能力和消费能力的差 xff0c 因为生产者和消费者的速度是不一样的 xff0c 有了这个缓冲
  • Go语言Windows10安装和环境配置详细步骤

    文章目录 前言一 下载Go安装包 xff1f 二 安装步骤1 安装2 验证是否安装成功 环境配置1 环境配置准备1 配置步骤 前言 提示 xff1a 我用的是windows10系统 xff1a 例如 xff1a Go安装包下载和在windo
  • C语言中scanf、gets、fgets,C++中cin、getline读取字符串的效率比较

    转自 xff1a https blog csdn net richenyunqi article details 89203826 可以使用C语言中scanf gets fgets xff0c C 43 43 中cin getline函数读
  • Android.mk和Android.bp的语句转换

    编译不同类型的模块 编译成 Native 动态库 Android mk include BUILD SHARED LIBRARY Android bp cc library shared 编译成 Native 静态库 Android mk
  • 学习c/c++ 推荐学习什么书籍?

    学习编程包含以下几个重要方面 xff1a 了解语言的语法 知道那些特性可以使用和何时使用 写出可读性好的代码 编译器可以理解 xff0c 但是下一个人是否可以阅读呢 xff1f 在一个更高层次设计结构良好的程序 为了学习一门语言 xff0c
  • 深入理解 http 反向代理(nginx)

    要理解什么是 反向代理 reverse proxy 自然你得先知道什么是 正向代理 forward proxy 另外需要说的是 一般提到反向代理 通常是指 http 反向代理 但反向代理的范围可以更大 比如 tcp 反向代理 在这里 不打算
  • 01-【Royal TSX】Mac上最好用的SSH工具Royal TSX使用教程

    参考文章 xff1a https www jianshu com p 0206980f529e
  • 数据结构:线性结构(C语言)

    文章目录 线性结构线性表什么是线性表线性表的抽象类型描述线性表的实现 广义表广义表定义多重链表 堆栈什么是堆栈堆栈的抽象数据类型描述堆栈的顺序存储实现堆栈的链式存储实现堆栈的应用 队列什么是队列队列的抽象数据类型描述队列的顺序存储实现队列的
  • 树(C语言)

    文章目录 树树的定义树的一些基本术语树的表示 树 树的定义 树 xff08 Tree xff09 xff1a n n 0
  • 堆(C语言)

    文章目录 堆 heap 什么是堆最小堆的操作操作集的实现 C语言 堆 heap 什么是堆 定义 堆 heap 是计算机科学中一类特殊的数据结构的统称 堆通常是一个可以被看做一棵树的数组对象 性质 结构性 xff1a 用数组表示的完全二叉树
  • VS2017中fopen等函数报错解决方法

    文章目录 VS2017中fopen 函数报错解决方法问题解决方法 VS2017中fopen 函数报错解决方法 问题 用VS2017写C语言代码的时候 xff0c 代码中使用了fopen 函数 xff0c 调试之后报错如下 xff1a err
  • 定位,浮动,BFC

    文章目录 1 xff0c 定位1 margin 与 padding 区别 xff1a 2 定位 xff1a 2 xff0c 元素分类 xff0c 浮动 xff0c BFC1 1 常见块级元素 xff1a 1 2 常见行内元素 xff1a 1
  • 表排序

    文章目录 表排序 表排序 思想 当待排数组中的元素不是简简单单的整数 xff0c 而是复杂的结构体 xff0c 那么移动元素所花费的时间就不能忽略不计了 xff0c 这时候我们要减少元素之间移动的次数了 表排序就是这么一个排序 xff0c
  • 循环链表的实现

    循环链表的实现 说明 参考资料 传智播客扫地僧的数据结构教学视频 线性表基本知识 参考 该实现的说明 C语言实现基于单向链表 xff0c 参考实现算法和数据的分离 实现 circular list h span class token ma
  • Ubuntu20.04安装与配置记录

    Ubuntu20 04安装与配置记录 原文地址 xff1a Ubuntu20 04安装与配置记录 一 Ubuntu系统盘制作 1 1 Windows环境下制作系统盘 下载Ubuntu系统 xff0c 选择桌面版 下载工具系统盘制作工具Ruf
  • C++单例写法记录

    C 43 43 单例写法记录 源码地址 一 饿汉式 1 1 静态指针 静态垃圾回收类 instance h ifndef INSTANCE H define INSTANCE H include lt string gt include l
  • 堆栈应用:表达式求值(C语言)

    文章目录 堆栈应用 xff1a 表达式求值 xff08 C语言 xff09 两个定义大致过程具体代码 堆栈应用 xff1a 表达式求值 xff08 C语言 xff09 两个定义 中缀表达式 xff1a 运算符号位于两个运算数之间 如 xff