递归算法实例应用(三)

简介: 递归算法实例应用(三):(POJ4132)四则运算表达式求值问题

递归算法实例应用(三)

四则运算表达式求值

Description

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

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

Input

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

Output

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

Sample Input

样例输入1:
34
样例输入2:
(2+3)*(5+7)+9/3

Sample Output

样例输出1:
34
样例输出2:
63

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;
}


By Ss1Two 2023/01/16

目录
相关文章
|
26天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的优化算法及其应用
【10月更文挑战第8天】 本文将探讨深度学习中常用的优化算法,包括梯度下降法、Adam和RMSProp等,介绍这些算法的基本原理与应用场景。通过实例分析,帮助读者更好地理解和应用这些优化算法,提高深度学习模型的训练效率与性能。
133 63
|
10天前
|
机器学习/深度学习 JSON 算法
二叉树遍历算法的应用场景有哪些?
【10月更文挑战第29天】二叉树遍历算法作为一种基础而重要的算法,在许多领域都有着不可或缺的应用,它为解决各种复杂的问题提供了有效的手段和思路。随着计算机科学的不断发展,二叉树遍历算法也在不断地被优化和扩展,以适应新的应用场景和需求。
19 0
|
21天前
|
存储 算法 搜索推荐
这些算法在实际应用中有哪些具体案例呢
【10月更文挑战第19天】这些算法在实际应用中有哪些具体案例呢
25 1
|
27天前
|
机器学习/深度学习 人工智能 算法
[大语言模型-算法优化] 微调技术-LoRA算法原理及优化应用详解
[大语言模型-算法优化] 微调技术-LoRA算法原理及优化应用详解
63 0
[大语言模型-算法优化] 微调技术-LoRA算法原理及优化应用详解
|
1月前
|
算法 安全 物联网
如何应用SM2算法进行身份认证
【10月更文挑战第5天】如何应用SM2算法进行身份认证
54 1
|
1月前
|
存储 算法 安全
SM2算法的应用场景有哪些?
【10月更文挑战第5天】SM2算法的应用场景有哪些?
64 1
|
1月前
|
存储 算法 安全
Python 加密算法详解与应用
Python 加密算法详解与应用
26 1
|
1月前
|
机器学习/深度学习 算法
深度学习中的优化算法及其应用
本文探讨了深度学习中常用的优化算法,包括梯度下降、随机梯度下降、动量方法和Adam方法。通过对比这些算法的优缺点及适用场景,帮助读者更好地理解和应用这些优化方法。
26 2
|
21天前
|
监控 算法 数据挖掘
HyperLogLog算法有哪些应用场景呢
【10月更文挑战第19天】HyperLogLog算法有哪些应用场景呢
14 0