使用栈 完成一个 计算器,使用语言PHP(源码分享)

本文详细介绍如何使用PHP实现一个简单的表达式求值系统。通过构建栈数据结构,解析并计算数学表达式,包括处理括号、运算符优先级及数字。文章提供了完整的代码示例,展示了从字符串解析到计算过程的每一步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

`<?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();

?>

`

转载于:https://my.oschina.net/u/3114929/blog/1617665

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值