使用栈完成高级计算器

1.堆栈的概念

一个先入后出(FILO-First In Last Oot)的有序列表。堆栈(stack)的限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,成为(Top),另一端为固定的一端,称为栈底(Bottom)。根据堆栈的定义而知,最先放入栈中元素在栈底,最后放入的元素在栈顶,而删除元素(或者取元素)刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。

2.堆栈的实际运用

(1)子程序的调用:在跳往子程序前,会先讲下个指令的地址存到堆栈中,直到子程序执行完毕后再讲地址取出,回到原来的程序中。
(2)处理递归调用:和子程序的调用类似,只是除了存储下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
(3)表达式的转换与求值。 //综合的计算器
(4)二叉树的遍历。 //前序遍历,后序遍历,中序遍历
(5)图形的深度优先(depth-first)搜索法。 //搜索算法


PHP实现基础栈及计算器

//+------------------------------------------------------------------------
//+								基础:自定义栈类
//+------------------------------------------------------------------------
/**
 * 基础栈类
 */
class MyStack{
	protected $top  = -1;
	protected $list = [];
	// 入栈
	public function push($val){
		$this->list[++$this->top] = $val;
	}
	// 出栈
	public function pop(){
		return $this->list[$this->top--];
	}
	// 显示全部
	public function showAll(){
		for ($i=$this->top;$i>=0;$i--){
			echo "第 {$i} 层:" . $this->list[$i] . "<br/>";
		}
	}
}

// 用例
$myStack = new MyStack();
$myStack->push('《设计原本》');
$myStack->push('《重构》');
$myStack->push('《人月神话》');
$myStack->push('《代码大全》');

$pop_value = $myStack->pop();
echo '弹出:'.$pop_value."<br/><br/>";

$myStack->showAll();





//+------------------------------------------------------------------------
//+						    扩展:使用栈的思路实现计算器类
//+------------------------------------------------------------------------
/**
 * 扩展计算器栈
 */
class CalculatorStack extends MyStack{
	// 获取栈顶元素的值
	public function topVal(){
		if( $this->top<0 ){
			return null;
		}
		return $this->list[$this->top];
	}
}
/**
 * 扩展计算器运算符栈
 */
class OperStack extends CalculatorStack{
	// 最新运算符的优先级与上一个运算符的优先级对比
	public function comparePri($newOper){
		$lastOper 		= $this->topVal();
		if( $lastOper==null ){
			return false;
		}
		$newOperPri 	= $this->PRI($newOper);
		$lastOperPri 	= $this->PRI($lastOper);
		if( $newOperPri>$lastOperPri ){
			return false;
		}
		return true;
	}
	// 获取运算符的优先级
	private function PRI($oper){
		if( in_array($oper, ['*','/']) ){
			return 1;
		}elseif( in_array($oper, ['+','-']) ){
			return 0;
		}else{
			throw new \Exception('当前运算符不支持!');
		}
	}
}

/**
 * 计算器
 */
class Calculator{
	private $numStack;		// 数字栈
	private $operStack;		// 运算符栈
	private $oper_str;
	
	public function __construct($oper_str){
		$this->numStack  = new CalculatorStack();
		$this->operStack = new OperStack();
		$this->oper_str  = $oper_str;
	}
	
	// 执行运算
	public function exec(){
		// 拆解运算字符串,依据类型分别入栈
		$strlen  = strlen($this->oper_str);
		$start	 = 0;
		while (true){
			$new_str = substr($this->oper_str, $start, 1);
			if( is_numeric($new_str) ){
				// 获取后面一个字符的类型,如果是数字,则拼接到当前的数字后面
				while (true){
					$next_str = substr($this->oper_str, $start+1, 1);
					if( is_numeric($next_str) ){
						$new_str .= $next_str;
						$start++;
					}else{
						break;
					}
				}
				$this->numStack->push($new_str);
				$start++;
			}else{
				$this->compareOperation($new_str);
				$start++;
			}
			if($start>=$strlen)break;
		}
		
		// 对栈中剩余数据进行运算
		$this->doOperation();
		
		// 数字栈的最后一个值,就是运算结果
		return $this->numStack->pop();
	}
	
	// 获取上一个运算符,如果优先级低于上一个,则进行依次出栈运算
	public function compareOperation($new_str){
		if( $this->operStack->comparePri($new_str) ){
			// 进入出栈运算
			$this->doOperation();
			// 再进行检测
			if( $this->operStack->comparePri($new_str) ){
				$this->compareOperation($new_str);
			}
		}
		$this->operStack->push($new_str);
	}
	
	// 执行一次出栈运算
	public function doOperation(){
		$num_01 = $this->numStack->pop();
		$num_02 = $this->numStack->pop();
		$oper	= $this->operStack->pop();
		switch ($oper){
			case '*':
				$operValue = $num_02 * $num_01;
				break;
			case '/':
				$operValue = $num_02 / $num_01;
				break;
			case '+':
				$operValue = $num_02 + $num_01;
				break;
			case '-':
				$operValue = $num_02 - $num_01;
				break;
		}
		
		// 将运算结果重新入数字栈
		$this->numStack->push($operValue);
	}
}

$oper_str 	= '300+2*6-20';
$calculator = new Calculator($oper_str);
$calc_val 	= $calculator->exec();
echo "<br/><br/><br/>公式 {$oper_str} 的运算结果为:{$calc_val}";


参考:

https://blog.csdn.net/wenximalong/article/details/8299749

https://blog.csdn.net/wenximalong/article/details/8300377

https://blog.csdn.net/wenximalong/article/details/8302009

https://blog.csdn.net/wenximalong/article/details/8302659

猜你喜欢

转载自blog.csdn.net/qw_xingzhe/article/details/80558630
今日推荐