【栈】实现高级计算器

实现一个计算器

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>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值