`<?php /* *@author fuhuaquan *@date 2018/1/28 */
header("Content-type:text/html;charset=utf-8");
//*构架一个类,实现栈这种数据结构
class Stack{
private $top=-1; //先定义一个指向栈顶的值,刚开始默认为栈底 -1
private $maxSize=50;
private $stack=array(); //用一个数组,存放数据。 实现入栈 出栈等系列操作
public function push($val){
if($this->top==$this->maxSize-1){ //先判断是否栈满,若没满则push入栈
echo "栈满..";
exit;
}
$this->top++; //先指针加1
$this->stack[$this->top]=$val; //入栈
return true;
}
public function pop(){
if($this->top==-1){ //先判断栈是否为空
echo '目前栈里还没数据..';
exit;
}
$topVal=$this->stack[$this->top]; //取出栈顶的值
$this->top--;
return $topVal;
}
public function showStack(){ //显示这个栈的数据,实现先入后出的效果
if($this->top==-1){
echo '目前栈里还没数据..';
exit;
}
echo '栈顶到栈底的数据依次为:'."\n";
for($i=$this->top;$i>-1;$i--){ //若不为空就遍历之
echo $this->stack[$this->top]."\n";
$this->top--;
}
}
/*
* [@desc](https://my.oschina.net/u/2009802) 判断是否为符号
* [@param](https://my.oschina.net/u/2303379) String $ch
*/
public function isOper($ch){
switch($ch){
case '*':
return true;
case '/':
return true;
case '+':
return true;
case '-';
return true;
default:
return false;
}
}
/*
*[@desc](https://my.oschina.net/u/2009802) 判断符号栈是否为空
*@param NULL
*/
public function isEmpty(){
if($this->top==-1){
return true;
}else{
return false;
}
}
/*
*@desc 取得栈顶的值,但是不出栈
*@param NULL
*/
public function getTop(){
if($this->top==-1){
return '此栈暂无数据..';
}
return $this->stack[$this->top];
}
/*
*@desc 判断符号优先级
*@param NULL
*/
public function PRI($ch_oper){
if($ch_oper=='*'||$ch_oper=='/'){
return 1;
}else if($ch_oper=='+'||$ch_oper=='-'){
return 0;
}
}
/*
*@desc 计算结果
*@param Int $num1
*@param Int $num2
*@param String $oper
*/
public function getResult($num1,$num2,$oper){
switch($oper){
case '*':
return $num2*$num1;
case '/':
return $num2/$num1; //后入先出,所以是num2/num1
case '+':
return $num2+$num1;
case '-':
return $num2-$num1; //后入先出,所以是num2-num1
}
}
}
//实例化一个数栈和一个符号栈
$numStack=new Stack;
$operStack=new Stack;
//扫描整个字符串,先只有个位数的
$str='30+20*5-20*5+10+10-10/2';
$index=0; //每次截取字符串的时候,就加一
$keepNum=''; //拼接数字
//先循环,当到字符串末尾的时候就break
while(1){
$ch=substr($str,$index,1); //每次截取一位
if(!$operStack->isOper($ch)){ //为数字的时候
$keepNum.=$ch; //拼上多位数
if($index==strlen($str)-1){
$numStack->push($keepNum);
}
//先去判断下一个字符是否为数字
if($operStack->isOper(substr($str,$index+1,1))){
$numStack->push($keepNum);
$keepNum=''; //清空keepNum 下次使用
}
}else{
//为运算符号的时候,先判断符号栈是否为空,如果为空就直接入栈
if($operStack->isEmpty()){
$operStack->push($ch);
}else{
/*判断刚得到的符号的优先级与目前栈顶的符号优先级谁高
* 1. 如果刚得到的符号优先级 小于等于 目前栈顶的符号优先级,就取出栈顶的符号,同时也从数栈取出两个值进行运算。
* 在把刚得到运算结果push入数栈,把刚得到的符号push入符号栈
*
* 2. 如果刚得到的符号优先级 大于 目前栈顶的符号优先级,直接push入符号栈。
*
*/
$ch_pri=$operStack->PRI($ch);//刚截取的运算符
$top_oper_pri=$operStack->PRI($operStack->getTop()); //栈顶的运算符
if($ch_pri > $top_oper_pri){ //如果刚截取的运算符 优先级大于 目前栈顶的优先级 ,就直接入符号栈
$operStack->push($ch);
}else if($ch_pri <= $top_oper_pri){ //否则就取出栈顶的运算符,进行运算
$num1=$numStack->pop();
$num2=$numStack->pop();
$oper=$operStack->pop();
$res=$operStack->getResult($num1,$num2,$oper); //计算,计算完的结果再次入 数栈,再把刚截取的符号入符号栈
$numStack->push($res);
$operStack->push($ch);
}
}
}
$index++; //加加 ,去截取下一个字符
if($index==strlen($str)){ //说明整个字符串扫描完毕
break;
}
}
/* 接下来就是把符号栈的符号和数栈的值 全部取出计算,最后留在数栈的那个值就是最终答案 */
while(!$operStack->isEmpty()){
$num1=$numStack->pop();
$num2=$numStack->pop();
$oper=$operStack->pop();
$res=$operStack->getResult($num1,$num2,$oper);
$numStack->push($res);
}
/* 取出最终留在数栈里的值就是最后结果 */
echo $str.'的最终答案:' .$numStack->getTop();
?>
`