韩顺平_PHP程序员玩转算法公开课(第一季)09_使用栈完成高级计算器(1)_学习笔记_源代码图解_PPT文档整理

文西马龙:http://blog.csdn.net/wenximalong/

堆栈——最神奇的数据结构


4.完成一个自定义优先级的综合计算器

把 字符串 3+2*6-2 把结果计算出来 你拿到的是字符串
问:
有没有一个函数,可以把字符串当做一个运算字符来执行的?
如果有,那么此函数的底层一定是用栈来实现的
即使你使用 一个函数就可以把这个算出,它的底层一定是堆栈来实现的

步骤
1.界面搞定
2.思路=====>分析图
3+2*6-2 从人的眼睛看 是 3+12-2=>15-2=>13,但是怎么让计算机知道呢, 计算机可没长眼睛,它怎么知道要先算2*6,然后再3+12,最后再15-2呢。计算机要扫描3 + 2 * 6 - 2一个个的字符


思路【怎么做】
思路[怎么做] ★现在的这个思路还不是很完美的,还是有考虑不周全的地方,先死后活,先有思路了,在后面再完善。★
1.程序扫描表达式,一个一个的扫描
2.当发现这个字符是数字的时候,直接入数栈
3.如果发现是运算符
3.1如果符号栈为空,就直接入符号栈
3.2如果符号栈不为空,就要判读。如果当前运算符的优先级小于等于符号栈顶的这个运算符的优先级,就计算,并把计算结果入数栈,然后把当前符号入栈(然后把当前符号入栈,此处会有问题,碰到复杂运算的时候,先考虑简单的,后面再优化,先死后活)
3.3如果符号栈不为空,就要判读。如果当前运算符的优先级大于符号栈顶的这个运算符的优先级,就入栈
4.当扫描完毕后,就依次弹出数栈和符号栈的数据,并计算,最终留在数栈的值,就是运算结果。

3+2*6-2
过程:
(1)
首先扫描到一个数字3,直接入数栈
(2)继续扫描发现是一个+,现在符号栈是空的,直接入栈
(3)继续扫描发现是一个数字2,直接入数栈
(4)继续扫描发现是一个*,现在符号栈不为空,并且*大于当前符号栈栈顶+的运算优先级,直接入栈
(5)继续扫描发现是一个数字6,直接入数栈
(6)继续扫描发现是一个-,现在符号栈不为空,并且-小于当前符号栈栈顶*的运算优先级,则计算。怎么计算呢,从数栈弹出两个数,从符号栈弹出一个运算符。即从数栈弹出6和2,然后从符号栈弹出*,并用变量接收。注意此时两个栈的top的指向变化
$num1=6;
$num2=2;
$oper=*;
$res=6*2; ==>12

图片大,在新窗口中打开图片,观看完整图片

(7)结果12要重新入栈

(8)继续扫描发现是一个-,直接入符号栈(然后把当前符号入栈,此处会有问题,碰到复杂运算的时候,先考虑简单的,后面再优化,先死后活)
(9)继续扫描发现是一个数字2,直接入数栈

至此扫描完毕
(10)
现在开始依次弹出,先从数栈弹出2和12,从符号栈弹出-,计算;然后再把结果10入数栈

(11)再从数栈弹出10和3,从符号栈弹出+,计算;然后再把结果13入栈,符号栈为空,最终结果13。


现在思路有了,怎样转成代码
思路----(长期艰苦的练习)----->代码
注意:在我们开发中,根据需要可以灵活的增加你需要的函数,不要想着一步到位

输入界面

calculator.php


	
		
	
	
		

高级计算器

请输入一个运算表达式

结果

jisuan.php


	
		
	
	
		

计算结果

isOper($ch)==true){ //说明是运算符 /* 3.如果发现是运算符 3.1如果符号栈为空,就直接入符号栈 3.2如果符号栈不为空,就要判读。如果当前运算符的优先级小于等于符号栈顶的这个运算符的优先级,就计算,并把计算结果入数栈,然后把当前符号入栈(然后把当前符号入栈,此处会有问题,碰到复杂运算的时候,先考虑简单的,后面再优化,先死后活) 3.3如果符号栈不为空,就要判读。如果当前运算符的优先级大于符号栈顶的这个运算符的优先级,就入栈 */ //把思路转成代码 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); } } }else{ //是数字,就入数栈 $numsStack->push($ch); } $index++; //让$index指向下一个字符 //判断是否已经扫描完毕 if($index==strlen($exp)){ break; } //当扫描完毕后,就break } /* 4.当扫描完毕后,就依次弹出数栈和符号栈的数据,并计算,最终留在数栈的值,就是运算结果。 */ //只要符号栈不空,就一直计算 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=$num1-$num2;要注意减的顺序,这样不对 $res=$num2-$num1; //注意顺序 break; case '*': $res=$num1*$num2; break; case '/': $res=$num2/$num1; //注意顺序 break; } return $res; } //返回栈顶的字符,只取,但是不出栈 public function getTop(){ return $this->stack[$this->top]; } //判断优先级的函数 //定义 *和/为1 +和-为0。先死后活,先考虑简单的,至于带括号的,在后面再改进。 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; } } //入栈的操作 public function push($val){ //先判断栈是否已经满了 if($this->top==$this->maxSize-1){ //5-1=4 0 1 2 3 4 echo'
栈满,不能添加'; return; } $this->top++; //先加再放 $this->stack[$this->top]=$val; //就入栈了 } //出栈的操作,就是把栈顶的值取出 public function pop(){ //判断是否栈空 if($this->top==-1){ echo'
栈空'; return; } //把栈顶的值,取出 $topVal=$this->stack[$this->top]; $this->top--; return $topVal; } //显示栈的所有数据的方法 public function showStack(){ if($this->top==-1){ echo'
栈空'; return; } echo'
当前栈的情况是...'; for($i=$this->top;$i>-1;$i--){ //反着显示 echo'
stack['.$i.']='.$this->stack[$i]; //从栈顶开始显示 } } } ?>

代码写这么长,有压力,一次性敲完了,然后运行,如果哪个地方出错了,就要排查了。
这么长的代码,你就是跟着视频敲,也 很容易出错。视频中的可以运行,你的就不一定了。代码敲多了,在敲'->'的时候少敲'-',或者operStack敲成operstack等等,都是很容易发生的。

如果运算式是:30+2*6-2的时候,上面的代码就出问题了

上面的jisuan.php代码就有需要改进的地方了,在下一篇中讲解。


韩顺平_PHP程序员玩转算法公开课_学习笔记_源代码图解_PPT文档整理_目录

你可能感兴趣的:(算法)