最近接触了一个有趣的需求:给定变量a、b、c、d等若干,要求由用户输入的普通四则运算字符串(包含加减乘除括号),算出具体的值。

例如,a=1,b=2,c=3,d=4,给出 a+b/(d-c),应计算出结果为3,若为 a*b/(c-1) 则应计算出结果为1

这种情况下,第一反应可能是用数字值将字符串里的变量替换,然后通过eval()执行。或者是将字符串中的每一项通过正则一个一个扣出来再进行计算。

但这样的逻辑太粗暴,代码也太丑陋,其实大可不必如此。 此时,让我们将目光移向美丽的数据结构与算法。

首先,我们了解一下 后缀表达式。

表达式一般由操作数(Operand)、运算符(Operator)组成,例如算术表达式中,通常把运算符放在两个操作数的中间,

这称为中缀表达式(Infix Expression),如A+B。我们日常生活中使用的就是此种方式

波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:

把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;

把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+

我们今天要探讨的就是后缀表达式

我们如何使用它呢?

首先我们要将平时用的中缀表达式转为后缀表达式。

在此之前,我们需要一种常见的数据结构:栈,在这一步,我们需要两个栈,操作数栈、运算符栈

1、从左至右扫描一中缀表达式。

2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数栈

3、若读取的是运算符

(1) 该运算符为左括号”(“,则直接存入运算符栈。

(2) 该运算符为右括号”)”,则输出运算符栈中的运算符到操作数栈,直到遇到左括号为止。

(3) 该运算符为非括号运算符:

(a) 若比运算符栈栈顶的运算符优先级高或相等,则直接存入运算符栈。

(b) 若比运算符栈栈顶的运算符优先级低,则输出栈顶运算符到操作数栈,并将当前运算符压入运算符栈。

4、当表达式读取完成后运算符栈中尚有运算符时,则依序取出运算符到操作数栈,直到运算符栈为空。

此时,将操作数栈转为一个字符串,它就是由我们输入的中缀表达式转化而来的后缀表达式

那么后缀表达式如何进行计算呢?

1、从左到右扫描后缀表达式。

2、如果扫描的项目是操作数,则将其压入操作数栈,并扫描下一个项目。

3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。

4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。

5、将运算结果重新压入栈。

6、重复步骤2-5,直到后缀表达式扫描完毕,栈中即为结果值。

Talk is cheap,let me show you the code

接下来是使用PHP编写的这样一个工具类。可以接受传入一个表达式和表达式各项对应值 的数组,给出计算之后的结果。

使用方式:

RPNotation::calculate($exp, $exp_values);

例如:

$exp = "a+b-(c*d)/e";

$exp_values = ["a" => 1, "b" => 2, "c" => 3, "d" => 2, "e" => 3];

RPNotation::calculate($exp, $exp_values);

结果会是1

代码内容 :

1, '-' => 1, '*' => 2, '/' => 2, "(" => 0, ")" => 0];

/*

params:

$exp-普通表达式,例如 a+b*(c+d)

$exp_values-表达式对应数据内容,例如 ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]

*/

public static function calculate($exp, $exp_values) {

$exp_arr = self::parse_exp($exp);//将表达式字符串解析为列表

if (!is_array($exp_arr)) {

return NULL;

}

$output_queue = self::nifix2rpn($exp_arr);

return self::calculate_value($output_queue, $exp_values);

}

//将字符串中每个操作项和预算符都解析出来

protected static function parse_exp($exp) {

$match = [];

preg_match_all(self::PATTERN_EXP, $exp, $match);

if ($match) {

return $match[0];

}else {

return NULL;

}

}

//将中缀表达式转为后缀表达式

protected static function nifix2rpn($input_queue){

$exp_stack = [];

$output_queue = [];

foreach($input_queue as $input) {

if (in_array($input, array_keys(self::EXP_PRIORITIES))){

if ($input == "(") {

array_push($exp_stack, $input);

continue;

}

if ($input == ")") {

$tmp_exp = array_pop($exp_stack);

while ($tmp_exp && $tmp_exp != "(") {

array_push($output_queue, $tmp_exp);

$tmp_exp = array_pop($exp_stack);

}

continue;

}

foreach(array_reverse($exp_stack) as $exp) {

if (self::EXP_PRIORITIES[$input] <= self::EXP_PRIORITIES[$exp]) {

array_pop($exp_stack);

array_push($output_queue, $exp);

}else {

break;

}

}

array_push($exp_stack ,$input);

}else {

array_push($output_queue, $input);

}

}

foreach(array_reverse($exp_stack) as $exp) {

array_push($output_queue, $exp);

}

return $output_queue;

}

//传入后缀表达式队列、各项对应值的数组,计算出结果

protected static function calculate_value($output_queue, $exp_values) {

$res_stack = [];

foreach($output_queue as $out) {

if (in_array($out, array_keys(self::EXP_PRIORITIES))) {

$a = array_pop($res_stack);

$b = array_pop($res_stack);

switch ($out) {

case '+':

$res = $b + $a;

break;

case '-':

$res = $b - $a;

break;

case '*':

$res = $b * $a;

break;

case '/':

$res = $b / $a;

break;

}

array_push($res_stack, $res);

}else {

if (is_numeric($out)) {

array_push($res_stack, intval($out));

}else {

array_push($res_stack, $exp_values[$out]);

}

}

}

return count($res_stack) == 1 ? $res_stack[0] : NULL;

}

}

PHP字符串运算结果,PHP 实现后缀表达式(接受四则运算字符串,输出计算结果,附代码)...相关推荐

  1. 九、中缀表达式转为后缀表达式

    使用栈将中缀表达式转为后缀表达式并计算 一.中缀表达式转换为后缀表达式 由于后缀表达式适合计算式进行计算,但是人对于较长的中缀表达式,很难将中缀表达式直接转换为后缀表达式,于是我们使用栈来实现中缀表达 ...

  2. Java堆栈的应用2----------中缀表达式转为后缀表达式的计算Java实现

    1.堆栈-Stack 堆栈(也简称作栈)是一种特殊的线性表,堆栈的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置进行插入和删除操作,而堆栈只允许在固定一端进行插入和删除 ...

  3. 前缀中缀后缀表达式的计算求值

    原文在这里 表达式 前缀表达式(波兰表达式) 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前 举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6 前缀表达式求值 ...

  4. 栈应用:中缀表达式转后缀表达式

    网上有很多关于中缀转后缀的文章,很多文章或多或少都有bug,包括一些教学视频,经过本人无数次测试,保证下面的代码运算结果的正确性!前提是你写的中缀表达式是正确的哈,没有做中缀表达式是否正确的的完整性校 ...

  5. 《数据结构》:中缀表达式转后缀表达式 后缀表达式的计算

    目录 一.基本概念 二.中缀表达式转后缀表达式 例       中缀表达式  2*(3+5)+7/1-4  转换为后缀表达式 三.后缀表达式的计算 例       后缀表达式  2 3 5 + * 7 ...

  6. 前缀、中缀、后缀表达式及中缀转后缀表达式

    前缀表达式: 不含括号的算术表达式,而且是将运算符写在前面,操作数写在后面的表达式. 求法: 首先从右往左扫描表达式,从右边第一个字符判断,如果当前字符是数字,则一直到字符串的末尾再记录下来:如果是运 ...

  7. 【数据结构与算法篇】什么是后缀表达式?

    什么是后缀.前缀.以及中缀表达式呢?他与我们平时在数学中见到的表达式有什么区别?第一次看这个名词,我还是有点蒙,难理解,所以做以下笔记,以便日后复习,也希望可以帮助读者,以相互促进. 文章目录 前言: ...

  8. Java数学表达式计算(中缀转后缀表达式)

    文章目录 前言 中缀表达式转后缀表达式 计算后缀表达式 计算形式公式 声明 前言 数学计算的加减乘除人脑算很简单,但是放到计算中却需要进行一些转换,在正式写Java计算数学表达式前,我们需要先来介绍两 ...

  9. 前缀表达式中缀表达式后缀表达式之间的转换JAVA代码实现

    一.前缀表达式 (1)中缀表达式转前缀表达式 (2)前缀表达式的计算 二.后缀表达式 (1)中缀表达式转后缀表达式 (2)后缀表达式的计算 三.中缀表达式直接计算 四.总结 代码实现的工具类Expre ...

最新文章

  1. pip安装提示PermissionError: [WinError 5]错误问题解决
  2. 用Python3解析html的几种操作方式,你都会用吗?
  3. 安装了git以后,idea类名颜色的含义
  4. Linux系统下.ko文件是什么文件?.so文件是什么文件?
  5. jquery根据value值php,表单php传值后jquery清除表单某项value问题
  6. 基于JAVA+SpringMVC+Mybatis+MYSQL的鲜花销售系统
  7. webpack前端构建工具学习总结(一)之webpack安装、创建项目
  8. Open×××多处理之-为什么不
  9. python银行排队系统仿真_单片机实现银行排队叫号系统Proteus仿真
  10. 一分钟搞定网页监控,实现网站链接百度自动推送
  11. Matlab仿真信号检测实验---基于贝叶斯准则的二元信号检测
  12. 使用freessl.orgq免费ssl证书
  13. [心得]最重要的事情只有一件!精华笔记
  14. 北大直博保送生论文涉嫌抄袭?原作者实名举报,北大南开火速调查
  15. 巨详细,大电流线性电源(LDO)原理,看完你就明白了
  16. 关系模式设计的问题 函数依赖
  17. 常用英语口语绝佳句型100句
  18. Python3字典合并的几种方法
  19. 2007年世界顶级防火墙排名(附下载地址)
  20. 2012服务器系统配置DNS,win服务器2012配置dns

热门文章

  1. 技术干货 | “选图预览并上传”的场景如何解?全网最全方案汇总来了
  2. 《Flutter in action》开放下载!闲鱼Flutter企业级实践精选
  3. 借助 Cloud Toolkit 快速创建 Dubbo 工程
  4. 性能诊断利器 JProfiler 快速入门和最佳实践
  5. 阿里云应用高可用服务公测发布
  6. 2018深圳云栖拉开帷幕,飞天技术汇五大专场邀你参加~
  7. 认识阿里云的产品逻辑:基础设施必须必业务跑得快
  8. 十年探索,云上明灯,re:Invent再启掀产业风暴
  9. 低代码发展专访系列之一:低代码平台产品的使用者都是谁?
  10. 第7届UBBF在迪拜举办 加强网络设施建设将加速产业发展成为共识