计算器 | 逆波兰表达式

来源:互联网 发布:淘宝怎么出售游戏账号 编辑:程序博客网 时间:2024/04/28 07:57

1.实现原理:

说明:在我原来做的逆波兰计算器中,postfix是用来表示逆波兰表达式的。但是和buptpatriot讨论后,想直接实现,下面是直接实现的方法:

首先,定义优先级:

function level($op) {switch ($op) {case '+':case '-':return 1;case '*':case '/':return 2;case '^':  return 3;}}


之后,扫描输入序列,读取输入的字符串,把其中的数字(可能是浮点型,负数)和操作符提取出来

收集浮点数:

function readin($expr) {$expr = str_split($expr);$len  = count($expr);$infix = array();$opts  = array('+','-','*','/','(',')');$num = "";for($i = 0; $i < $len; $i++) {if(in_array($expr[$i], $opts) || ($i == $len-1)) {if($num = floatval($num)) {array_push($infix, $num);$num = "";}if($expr[$i] == '-' && ($expr[$i-1] == NULL || $expr[$i-1] == '(') && (is_numeric($expr[$i+1]) || $expr[$i+1] == '(')) {$expr[$i] = '^'; //unary negotion}array_push($infix, $expr[$i]);}else {$num .= $expr[$i];}}var_dump($infix);return $infix;}


对于否定符号(-)做处理:

if($expr[$i] == '-' && ($expr[$i-1] == NULL || $expr[$i-1] == '(') && (is_numeric($expr[$i+1]) || $expr[$i+1] == '(')) {$expr[$i] = '^'; }

此时,否定符号'-'转化成'^'

1) 如果是数字,则存入栈 postfix 中;

2) 如果是运算符:

        2.1)是 ‘(’ ,则存入栈 stack 中;

        2.2)是‘+’,‘-’,‘*’,‘/’,‘’,则检查栈stack是否为空:

               2.2.1)stack 为空:则存入栈内

               2.2.2 ) stack不为空,执行下面的操作:

                           从stack中弹出一个元素op

                           如果这个元素的不是 ‘(’ 且弹出元素的优先级大于当前扫描元素的优先级,就将弹出元素存入postfix栈内,同时从postfix中弹出2个元素a,b,计算a op b的结 果,将其存入postfix中;

                           否则,把弹出元素op重新压入栈stack内   

                           最后,当前扫描到的运算符入栈stack

         2.3) 是‘^’ :执行下面的操作:

                            从postfix中弹出1个元素a,将(0-a)存入postfix中;

         2.4) 是‘)’ :执行下面的操作:

                            弹出元素存入postfix栈内,同时从postfix中弹出2个元素a,b,计 算a op b的结果,将其存入postfix中;

                            直到弹出元素为'(';          

画一个表来看:4/((3-1)*2) = 1的计算过程

currentstackpostfix4empty4//4(/(4(/((43/((43-/((-431/((-431)/(42*/(*422/(*422)/44 empty1(result)

                  

2.php 代码:

<html><head><title>Reverse Polish Notation Calculator</title></head><body><h1>Calculator</h1><h3>by wusuopubupt</h3><form id="my_form" method="POST" action="<?php echo $_SERVER['SCRIPT_NAME'];?>"><input type="text" name="expr" placeholder="input expression to calculate!"/></form><?phpif(isset($_POST['expr'])) {$expr = readin($_POST['expr']);$result = cal($expr);echo "result is:";var_dump($result);}function readin($expr) {$expr = str_split($expr);$len  = count($expr);$infix = array();$opts  = array('+','-','*','/','(',')');$num = "";for($i = 0; $i < $len; $i++) {if(in_array($expr[$i], $opts) || ($i == $len-1)) {if($num = floatval($num)) {array_push($infix, $num);$num = "";}if($expr[$i] == '-' && ($expr[$i-1] == NULL || $expr[$i-1] == '(') && (is_numeric($expr[$i+1]) || $expr[$i+1] == '(')) {$expr[$i] = '^'; }array_push($infix, $expr[$i]);}else {$num .= $expr[$i];}}var_dump($infix);return $infix;}function cal($expr) {$postfix_expr = infix2postfix($expr);var_dump($postfix_expr);$len = count($postfix_expr);$stack = array();$result = 0;for($i = 0; $i < $len; $i++) {$var = $postfix_expr[$i];if(is_numeric($var)) {array_push($stack, $var);}else {if($var != '^') {$rhs = array_pop($stack); //right hand side$lhs = array_pop($stack); //left  hand sidearray_push($stack,operate($lhs,$var,$rhs));}else { $rhs = 0 - array_pop($stack);array_push($stack, $rhs);} }}return array_pop($stack);}function infix2postfix($expr) {$len = count($expr);$stack = array();$postfix = array();for($i = 0; $i < $len; $i++) {if(is_numeric($expr[$i])) {$postfix[] = $expr[$i];}else {if($expr[$i] == '(') {array_push($stack, $expr[$i]);}if($expr[$i] == '+' || $expr[$i] == '-' || $expr[$i] == '*' || $expr[$i] == '/' || $expr[$i] == '^') {if(!empty($stack)){$op = array_pop($stack);if($op != '(' && (level($op) >= level($expr[$i]))) {array_push($postfix,$op);}else {array_push($stack, $op);}}array_push($stack, $expr[$i]);}if($expr[$i] == ')') {while(($op = array_pop($stack)) != '(') {array_push($postfix,$op);}}}}while(($last_op = array_pop($stack)) != NULL){array_push($postfix, $last_op);}return $postfix;}function operate($left,$op,$right) {switch($op) {case '+':return $left + $right;case '-':return $left - $right;case '*':return $left * $right;case '/':return $left / $right;}}function level($op) {switch ($op) {case '+':case '-':return 1;case '*':case '/':return 2;case '^':  return 3;}}?></body></html>


3.运行结果:

输入:4/((3-1)*2) 

输出:




包含 否定符号的结果:

输入:-(-1.2+1.8)/(1/3.0)

输出:


原创粉丝点击