实现一个计算器
9+2*8-2
30+2*6-1
7*2-3*5-2
实现思路:
1、程序扫描表达式
2、发现是数字就入数字栈(这里要特别注意,当数字不是一位的情况)
3.如果发现是运算符
a)如果符号栈为空,就直接入符号栈
b)如何符号栈,不为空,就判断
I) 如果当前运算符的优先级小于等于符号栈顶的这个运算符的优先级,就计算,并把计算结果入数栈.然后把当前符号入栈
这里要特别注意比如13-11-2的例子!当两个减号优先级相同时,如果不把已有的减号计算,就会计算成先计算11-2再用13-9=4的错误答案。所以这个地方是个while循环。
II) 如果当前运算符的优先级大于符号栈顶的这个运算符的优先级,就入栈.
4、最后把所有的数都出栈,计算,留在数栈中的值就是最后结果
<html>
<head>
<meta http-equiv='content-type' content='text/html;charset=gbk'/>
</head>
<?php
// $exp=$_GET['exp'];
// $exp='9+2*8-3'; //[人眼睛3+12-2 =>15-2=>13]
// $exp='304+10*6-10';
$exp='71*2-50*3-3-67*6+80';//-333
$numsStack=new MyStack();
$operStack=new MyStack();
$keepNum='';//专门用于拼接数字
$index=0;//$index就是一个扫描标记
while(true){
//依次取出字符
$ch=substr($exp,$index,1);
//判断$ch是不是一个运算符
if($operStack->isOper($ch)==TRUE){
//是运算符
/**
*/
if($operStack->isEmpty()){
$operStack->push($ch);
}else{
/*
//需要一个函数来获取运算符的优先级 *和/的优先级为1 ,+和-为0
$chPRI=$operStack->PRI($ch);
$stackPRI=$operStack->PRI($operStack->getTop());
if($chPRI<=$stackPRI){
//从数栈依次出栈两个数
$num1=$numsStack->pop();
$num2=$numsStack->pop();
//再从符号栈取出一个运算符
$oper=$operStack->pop();
//这里还需要一个计算的函数
$res=$operStack->getResult($num1,$num2,$oper);
//把$res入数栈
$numsStack->push($res);
//把当前这个符号再入符号栈 ?????这里是有问题的,一会儿再来解决
$operStack->push($ch);
}else{
$operStack->push($ch);
}
*/
while(!$operStack->isEmpty()&&$operStack->PRI($ch)<=$operStack->PRI($operStack->getTop())){
//从数栈依次出栈两个数
$num1=$numsStack->pop();
$num2=$numsStack->pop();
//再从符号栈取出一个运算符
$oper=$operStack->pop();
//这里还需要一个计算的函数
$res=$operStack->getResult($num1,$num2,$oper);
//把$res入数栈
$numsStack->push($res);
//把当前这个符号再入符号栈 ?????这里是有问题的,一会儿再来解决
}
$operStack->push($ch);
}
}else{
//是数字
$keepNum.=$ch;
//先判断是否已经到了字符串的最后,如果已经到最后了,就直接入栈
//判断一下$ch字符的下一个字符是数字还是符号
if($index==strlen($exp)-1){
$numsStack->push($keepNum);
}else{
if($operStack->isOper(substr($exp,$index+1,1))){
$numsStack->push($keepNum);
$keepNum='';
}
}
}
$index++;//让index指向下一个字符
//判断是否已经扫描完毕
if($index==strlen($exp)){
break;
}
//当扫描完毕后就break;
}
//只要符号栈不空就一直计算
while(!$operStack->isEmpty()){
$num1=$numsStack->pop();
$num2=$numsStack->pop();
$oper=$operStack->pop();
$res=$operStack->getResult($num1,$num2,$oper);
$numsStack->push($res);
}
//当退出while后,一定有一个数,这个数就是最终结果
echo $exp.'='.$numsStack->getTop();
//自定义的栈
class MyStack{
private $top=-1;//默认是-1,表示该栈是空的
private $maxSize=5;//$maxSize表示栈的最大容量
private $stack=array();
//计算的函数
public function getResult($num1,$num2,$oper){
$res=0;
switch($oper){
case '+':
$res=$num1+$num2;
break;
case '-':
$res=$num2-$num1;
break;
case '*':
$res=$num1*$num2;
break;
case '/':
$res=$num2/$num1;
break;
}
return $res;
}
//返回栈顶的字符,只是取出不出栈
public function getTop(){
return $this->stack[$this->top];
}
//判断优先级的函数
public function PRI($ch){
if($ch=='*'||$ch=='/'){
return 1;
}else if($ch=='+'||$ch=='-'){
return 0;
}
}
//判断栈是否为空
public function isEmpty(){
if($this->top==-1){
return TRUE;
}else{
return FALSE;
}
}
//增加一个函数【提示:在我们开发中,根据需要可以灵活增加需要的函数】
//判断是不是一个运算符
public function isOper($ch){
if($ch=='-'||$ch=='+'||$ch=='*'||$ch=='/'){
return TRUE;
}else{
return FALSE;
}
}
//注意类里面的变量一定要用$this->xxx,不然就杯具了
//入栈的操作
public function push($val){
//先判断栈是否已经满了
if($this->top==$this->maxSize-1){
echo '<br/>栈满,不能添加';
return;
}
$this->top++;
$this->stack[$this->top]=$val;
}
//显示栈的所有数据的方法
public function showStack(){
if($this->top==-1){
echo '<br/>栈空';
return;
}
echo '<br/>当前栈的情况是......';
for($i=$this->top;$i>-1;$i--){
echo '<br/>stack['.$i.']='.$this->stack[$i];
}
}
//出栈的操作,就是把栈顶取出
public function pop(){
//判断是否是栈空
if($this->top==-1){
echo '<br/>栈空';
return;
}
//把栈顶的值,取出
$topVal=$this->stack[$this->top];
$this->top--;
return $topVal;
}
}
?>
</html>