递归算法实例应用(三)

news2024/12/27 3:45:47

递归算法实例应用(三)

四则运算表达式求值

Description

给你一个字符串表达式 str ,请你实现一个基本计算器来计算并返回它的值。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数 。

Input

一行,一个四则运算表达式。'*‘表示乘法,’/'表示除法

Output

一行,该表达式的值,保留小数点后面两位

Sample Input

样例输入134
样例输入2(2+3)*(5+7)+9/3

Sample Output

样例输出134
样例输出263

Tips

  • 1 <= s.length <= 3 * 105
  • str 由数字、'+''-''('')'组成
  • str 表示一个有效的表达式
  • '+‘和’-'不能用作一元运算(例如, “+1” 和 "+(2 + 3)" 无效)
  • 输入中不存在两个连续的操作符
  • 每个数字和运行的计算将适合于一个有符号的32位整数



算法思想:

通过对题目的分析知道该题为递归形式定义的问题,其递归形式可描述如下:
请添加图片描述

所以,从递归定义出发,本题应分为三部分进行讨论,即表达式、项、因子,因为这三者相互嵌套组成了输入的一个表达式。

  1. 表达式,可以是一个单独的项,也可以由 项1 op 项2 组成。
  2. 项,可以是一个单独的因子,也可以由 因子1 op 因子2 组成。
  3. 因子,可以是一个单独的整数,也可以由 ( 表达式 ) 组成。

三者相互嵌套,递归表达构成了一个四则运算表达式。递归的终止条件为3中由整数形式定义的因子。

所以我们可以通过三个函数来实现对表达式、项、因子的求值。




代码逻辑:

  1. 一次性读取输入的表达式,

  2. 对于“表达式函数”而言有两种情况:

    • 该表达式为一个单独的项,此时仅需通过“项函数”读取改项的值,并作为结果返回即可

    • 若该表达式为 项1 op 项2,此时op应为‘+’或‘-’,先从输入缓冲区中消耗掉该op运算符,然后再读取下一个项的值,再做对应操作符计算即可。

    • 代码逻辑为:

    • int Expression_Value() {
          int result = Term_Value();      //取项1的值
          while (true) {
              char operation = peek();    //查看输入流中下一个字符
              if (operation == '+' || operation == '-') {
                  getchar();              //消耗掉输入流中下一个的'+'或'-'运算符
                  int nextTerm_Value = Term_Value();//若操作符为+或-,则应有项2,记录项2
                  if (operation == '+') {
                      result += nextTerm_Value;//更新结果为项1+项2
                  } else {
                      result -= nextTerm_Value;//更新结果为项1-项2
                  }
              } else {//若输入流中下一个字符不为+或-则表明该表达式为单项组成
                  break;
              }
          }
          return result;
      }
      
  3. 对于“项式函数”有两种情况:

    • 该项为一个单独的因子,此时仅需通过“因子函数”读取该因子的值,并作为结果返回即可

    • 若该项为 因子1 op 因子2,此时op应为‘*’或‘/’,先从输入缓冲区中消耗掉该op运算符,然后再读取下一个表达式的值,再做对应操作符计算即可。

    • 代码为:

    • int Term_Value() {
          int result = Factor_Value();//取因子1的值
          while (true) {
              char operation = peek();//查看输入流中下一个字符
              if (operation == '*' || operation == '/') {
                  getchar();//消耗掉这个'*'或'/'运算符
                  int nextFactor_Value = Factor_Value();//若操作符为*或/,则应有因子2,记录因子2
                  if (operation == '*') {
                      result *= nextFactor_Value;//更新结果为因子1*因子2
                  } else {
                      result /= nextFactor_Value;//更新结果为因子1/因子2
                  }
              } else {//若输入流中下一个字符不为*或/则表明该项为单因子组成
                  break;
              }
          }
          return result;
      }
      
  4. 对于“因子函数”同样也有两种情况:

    • 该因子为一个单独的整数因子,此时仅需将因子字符串转换成对应的整数类型,并作为结果返回即可。

    • 若该项为 ( 表达式 ),此时因子由表达式递归而成,而表达式被左右括号包裹着,所以我们应先从输入缓冲区中消耗掉左括号,然后调用“表达式函数”求该表达式的值,并将该表达式的值作为结果返回。

    • 其中关于字符串转整形数据,可按照秦九韶算法思想进行转换,比较简单,不再阐述,读者自行模拟一遍即可领会。

    • 代码为:

    • int Factor_Value() {
          int result = 0;//记录这个因子的结果
          char ch = peek();//查看输入流中下一个字符
          if (ch == '(') {//若下一个字符为(,则表明该因子为'(因子)'的形式
              getchar();//消耗掉'('
              result = Expression_Value();
              getchar();//消耗掉')'
          } else {//若下一个字符不为(,则表明该因子为整数形式,所以根据将字符转化为整形数字
              while (isdigit(ch)) {//如‘2’‘7’,result=(10*0+2)*10+7=2*10+7
                  result = 10 * result + (ch - '0');
                  getchar();//消耗掉该位字符。
                  ch = peek();
              }
          }
          return result;
      }
      
  5. 关于peek()函数的一点说明:

    • 该方法为编者自定义的一个函数,主要实现C++中int peek()函数功能。即返回在输入流中的下一个字符或如果是处于被入的文件的结尾处返回EOF。

    • peek()函数不会把字符从流中移除,也不改变字符所处位置。

    • 代码为:

    • int peek() {
          int ch = getchar();//读入一个字符
          ungetc(ch, stdin);//将该字符重新放入该字符在输入缓冲区中所处位置
          return ch;
      }
      



代码整合:

#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

/* 表达式求值题目函数声明 */

int Expression_Value();     //求一个表达式的值
int Term_Value();           //求一个项的值
int Factor_Value();         //求一个因子的值

int main() {
    printf("%d\n", Expression_Value());//输出表达式的值。
    return 0;
}

int peek() {
    int ch = getchar();//读入一个字符
    ungetc(ch, stdin);//将该字符重新放入该字符在输入缓冲区中所处位置
    return ch;
}

//计算表达式的值
int Expression_Value() {
    int result = Term_Value();      //取项1的值
    while (true) {
        char operation = peek();    //查看输入流中下一个字符
        if (operation == '+' || operation == '-') {
            getchar();              //消耗掉输入流中下一个的'+'或'-'运算符
            int nextTerm_Value = Term_Value();//若操作符为+或-,则应有项2,记录项2
            if (operation == '+') {
                result += nextTerm_Value;//更新结果为项1+项2
            } else {
                result -= nextTerm_Value;//更新结果为项1-项2
            }
        } else {//若输入流中下一个字符不为+或-则表明该表达式为单项组成
            break;
        }
    }
    return result;
}

//计算项的值
int Term_Value() {
    int result = Factor_Value();//取因子1的值
    while (true) {
        char operation = peek();//查看输入流中下一个字符
        if (operation == '*' || operation == '/') {
            getchar();//消耗掉这个'*'或'/'运算符
            int nextFactor_Value = Factor_Value();//若操作符为*或/,则应有因子2,记录因子2
            if (operation == '*') {
                result *= nextFactor_Value;//更新结果为因子1*因子2
            } else {
                result /= nextFactor_Value;//更新结果为因子1/因子2
            }
        } else {//若输入流中下一个字符不为*或/则表明该项为单因子组成
            break;
        }
    }
    return result;
}

//计算因子的值
int Factor_Value() {
    int result = 0;//记录这个因子的结果
    char ch = peek();//查看输入流中下一个字符
    if (ch == '(') {//若下一个字符为(,则表明该因子为'(因子)'的形式
        getchar();//消耗掉'('
        result = Expression_Value();
        getchar();//消耗掉')'
    } else {//若下一个字符不为(,则表明该因子为整数形式,所以根据将字符转化为整形数字
        while (isdigit(ch)) {//如‘2’‘7’,result=(10*0+2)*10+7=2*10+7
            result = 10 * result + (ch - '0');
            getchar();//消耗掉该位字符。
            ch = peek();
        }
    }
    return result;
}

B y ⋯ S s 1 T w o ⋯ 2023 / 01 / 16 By\cdots Ss1Two\cdots2023/01/16 BySs1Two2023/01/16

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

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

相关文章

编写设备驱动之i2c_client

编写设备驱动之i2c_client 文章目录编写设备驱动之i2c_client参考资料&#xff1a;一、I2C总线-设备-驱动模型二、 编译i2c_driver三、编写测试程序四、多种方法生成i2c_client并测试4.1 在用户态生成4.2 编写代码4.3 使用设备树生成2. IMX6ULL4.4 上机测试致谢参考资料&#x…

prometheus的remotewrite解析

特性 目的是为了向远端的存储写入数据。 为了提高写入效率&#xff0c;Prometheus在将采集到的samples写入远程存储之前&#xff0c;会先缓存在内存队列中&#xff0c;然后打包发送给远端存储。而这个内存队列的配置参数&#xff0c;对于Prometheus写入远程存储的效率影响较大…

《MySQL高级篇》十一、事务基础知识

文章目录1. 数据库事务概述1.1 存储引擎支持情况1.2 基本概念1.3 事务的ACID特性1.4 事务的状态2. 如何使用事务2.1 显式事务2.2 隐式事务2.3 隐式提交数据的情况2.4 使用举例1&#xff1a;提交与回滚2.5 使用举例2&#xff1a;测试不支持事务的Engine2.6 使用举例3&#xff1a…

STL中的队列用法整理

STL中的队列先进先出队列&#xff08;FIFO&#xff09;主要方法代码示例输出优先级队列模版原型主要对方法有代码示例int的大顶堆运行结果int的小顶堆运行结果使用自定义的比较函数的优先队列代码示例运行结果双端队列主要方法示例运行结果有关双端队列的题目先进先出队列&…

Vue生命周期,总也学不会,所以我详细整理了一下

今天&#xff0c;我和大家一起来对vue生命周期做一个整理和思考&#xff0c;希望有缘人看到我的年度整理和思考&#xff0c;如果觉得靠谱呢&#xff0c;就交个朋友&#xff0c;如果觉得我整理的不足&#xff0c;就请指出&#xff0c;让我们一起进步&#xff0c;让我们2023年能共…

单链表

插入&#xff1a; head 表示头结点的下标 e[i] 表示节点i的值 ne[i] 表示节点i的next指针是多少 idx 存储当前已经用到了哪个点 步骤&#xff1a;1.初始化head 2.将x插到头结点 3.插入&#xff1a;将x插到下标是k的点后面 4.将x插到下标是k的点后面 5.将下标是k的点后面…

springboot,vue影院订票系统

开发工具&#xff1a;IDEA服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8项目构建&#xff1a;maven数据库&#xff1a;mysql5.7系统用户前台和管理后台两部分&#xff0c;项目采用前后端分离前端技术&#xff1a;vue elementUI服务端技术&#xff1a;springbootmybatis项目功…

集合框架及背后的数据结构

集合框架及背后的数据结构1. 介绍2. 学习的意义2.1 Java 集合框架的优点及作用2.2 笔试及面试题3. 接口 interfaces3.1 基本关系说明3.2 Collection 接口说明3.3 Collection 常用方法说明3.4 Collection 示例3.5 Map 接口说明Map3.6 Map 常用方法说明3.7 Map 示例4. 实现 class…

免费AI改图神器,一个万能宝藏在线工具箱

说到工具箱&#xff0c;无论是在线工具&#xff0c;还是软件应用都非常多。 比如想要抠一张图片&#xff0c;如果专业处理&#xff0c;那么会使用到 Photoshop&#xff0c;需要一定的学习成本&#xff0c;想要更快捷处理&#xff0c;那么会直接使用在线工具&#xff0c;网络上…

Secret

目录 文章目录目录本节实战前言1、Opaque Secret1.创建Secret&#xff08;1&#xff09;通过data字段来创建secret资源对象&#xff08;2&#xff09;通过stringData字段来创建secret资源对象&#xff08;3&#xff09;通过kubectl create命令来创建Opaque类型的Secret资源2.使…

ROS2 基础概念 参数

ROS2 基础概念 参数1. Parameters2. 参数3. 参数查看4. 参数设置5. 参数保存6. 参数加载1. Parameters 指令功能ros2 param delete /node parameter删除参数值ros2 param describe /node parameter显示参数的相关描述ros2 param dump /file将参数保存到一个文件中ros2 param g…

LinuxDeployQT打包QT程序

系统&#xff1a;ubuntu20.04官网可直接下载使用https://github.com/probonopd/linuxdeployqt/releases&#xff0c;但是因为不支持ubuntu20所以本文通过下载源码编译的方式编译linuxdeployqt安装编译相关依赖sudo apt-get install git g libgl1-mesa-dev wget安装QTsudo apt-g…

大数据之Kafka Shell命令和Java API

文章目录前言一、Kafka相关Shell命令&#xff08;一&#xff09;创建并查询Topic&#xff08;二&#xff09;删除Topic&#xff08;三&#xff09;增加Topic的分区&#xff08;四&#xff09;生产数据到Topic&#xff08;五&#xff09;从Topic消费数据总结前言 #博学谷IT学习…

机器学习笔记之深度玻尔兹曼机(一)玻尔兹曼机系列整体介绍

机器学习笔记之深度玻尔兹曼机——玻尔兹曼机系列整体介绍引言关于含隐变量模型的对数似然梯度玻尔兹曼机受限玻尔兹曼机深度信念网络深度玻尔兹曼机引言 从本节开始&#xff0c;将介绍玻尔兹曼机系列的最后一个模型——深度玻尔兹曼机(Deep Boltzmann Machine,DBM) 关于含隐…

【状态设计优化DP】P4310 绝世好题

不愧是绝世好题和abc那道E一样&#xff0c;也是重新定义状态来优化转移复杂度的DP(56条消息) Atcoder Beginner Contest E - Work or Rest_lamentropetion的博客-CSDN博客这种其实就是通过转移方式的特殊性来设计状态&#xff0c;从而降低复杂度其实我感觉降低复杂度优化就是因…

数据结构——括号匹配问题

这是一道常见的经典的数据结构中栈的问题。题目&#xff1a;20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09;我们运用C语言实现这个问题。有效括号调用栈由于要涉及到栈的问题&#xff0c;不可避免的要运用栈的函数接口。比较直接的方法是&#xff0c;直接复制 栈 的代…

通过windows程序计划设定nginx开机自启动

通过windows程序计划设定nginx开机自启动1、按下win键输入计划&#xff0c;回车2、找到windows目录&#xff0c;在当下目录创建新任务3、自定义名称描述4、将触发设定为开机自启动5.点击下一步&#xff0c;程序或脚本选择nginx.exe所在目录&#xff0c;要把下面的起始于 处填上…

算法训练营 day20 二叉树 最大二叉树 合并二叉树 二叉搜索树中的搜索 验证二叉树

算法训练营 day20 二叉树 最大二叉树 合并二叉树 二叉搜索树中的搜索 验证二叉树 最大二叉树 654. 最大二叉树 - 力扣&#xff08;LeetCode&#xff09; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值…

《Linux Shell脚本攻略》学习笔记-第十一章

11.1 简介 本章将会讲述如何获取相关网络分组。CPU占用率、磁盘使用情况以及东台调用的更多信息。 11.2 使用tcpdump跟踪分组 tcpdump需要以root身份运行。 关键字port可以只显示出发往或者来自特定端口的分组 src修饰符配合特定的“关键字-值”就可以指定源文件中的这类分组。…

Linux chown 命令

Linux chown&#xff08;英文全拼&#xff1a;change owner&#xff09;命令用于设置文件所有者和文件关联组的命令。Linux/Unix 是多人多工操作系统&#xff0c;所有的文件皆有拥有者。利用 chown 将指定文件的拥有者改为指定的用户或组&#xff0c;用户可以是用户名或者用户 …