计算器 | 逆波兰表达式

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的计算过程

currentstackpostfix
4empty4
//4
(/(4
(/((4
3/((43
-/((-43
1/((-431
)/(42
*/(*42
2/(*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>
<?php
if(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 side
				array_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)

输出:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值