完成简单的四则运算(包含小括号)(栈)

设计目标:借用栈的特性(后进后出),可将先进入的数据进行暂时存储,在得到运算符后进行运算。

考虑因素:因为四则运算中既包含一级运算也包含二级运算(优先级高),所以需对这两种情况进行不同的区分,此外对于出现小括号时压栈和出栈的情况也要进行考虑。

主要思路
由于栈的特性,我们可以在拿到运算符时进行对前一个运算符进行判断,借此来完成数值的运算。

1)、建立两个栈结构、一个存储运算符(栈A)、一个存储数值(栈B)

2)、针对六种情况进行不同的区分( 数值、(+,-)、(*,/)、=、(、) )
对于整个运算式(String类型),进行逐个字符的提取,加以判断

①对于数值(包含小数点):由于提取到的是字符类型(1位),所以首先应该在判断出数值时应该循环提取,这时可用ASCAII码进行判断,对判断出的字符类型进行转换,拼接。因为小数点的存在,就需要设立一个标志来标记小数点的出现,依此来完成小数部分的拼接。随后,压入栈B。
②对于一级运算符(+、-):一级运算符级别较低,出现时,对栈A栈顶进行判断。若不为空且不是‘(’,栈A出栈得到运算符,栈B出栈可得到数值(2个),进行运算的出结果压入栈B。此处需注意2个数值的出栈顺序,会影响到运算结果。
③对于二级运算符(*、/):运算级别高于一级运算符,出现时,对栈A栈顶进行判断。若不为空、‘(’、+、-时,即可进行运算,运算过程同②。
④对于‘(’:直接压入栈中。
⑤对于‘)’:由于左括号和右括号是相互匹配的,在出现时,需对栈A进行遍历运算,直到得出‘(’时,停止运算。
⑥对于‘=’:‘=’号的出现意味着运算结束,此时需清空栈A,将栈B栈顶元素进行返回。

PS:此处要提醒重要的一点,‘-’ 号的出现会影响一级运算符运算结果的正确性
如:3-4*5+6+7 运算到“3-20+6”时,此时会输入一个‘+’号并且运算前一个‘+’号,但20的前面有一个‘-’号,若直接运算就得到“3-26+”,很明显是错误的,正确结果应为“3-14+”。所以在进行一级运算时,若前一符号为‘-’,则应将该计算的‘+’变‘-’,‘-’变‘+’。

设计方案
①定义一个栈的结构,使用数组来完成数据的存储,需实现的方法:栈的初始化、压栈函数、出栈函数、返回栈顶数据(并不出栈,用以判断)。
②设计一个总的运算函数,形参为运算式,对运算式进行切割,针对不同的情况进行不同的处理。
③由于在很多情况中都会进行出栈运算,所以可将该运算进行封装,减少代码的重复性,提高可用性。

具体实现
①栈结构(由于存储数据类型的不同、此处我定义为object数组,也可以使用范型)

	//定义栈
	private Object[] objStack;
	 //定义栈长
 	private int Max_num;
	 //定义栈顶指针
 	private int top;

	//初始化
 	public StoreStack() {
 		 Max_num = 20;      //定义能够存储20个数
  		objStack = new Object[Max_num+1];   //top指针占一个位置
  		top = 0;
 	}
 	//是否满
	private boolean fullStack() {
 		 if(this.top == this.Max_num) {
 		  return true;
	  }
		  return false;
	 }
	 //是否空
	 public boolean emptyStack() {
 		 if(this.top == 0) {
		   return true;
	  }
		  return false;
	 }
	 
	 //入栈函数
	 public void push(Object obj) {
		  //判断是否栈满
		  if(fullStack()) {
 			  System.out.println("栈满,无法添加");
		  }else {
			   objStack[top++] = obj;
	  	} 
	 }
	 //出栈函数
	 public Object popStack() {
		  //判断是否栈空
		  if(emptyStack()) {
		 	  //若空,返回null
		 	  return null;
		  }
 		 return objStack[--top];
 	}
 	//查看栈顶元素
	 public Object catStackTop() {
		  if(top == 0) {
			   return null;
 		 }else {
 			  return objStack[top-1];       //栈顶指针比数据高一位
		  }	
	}

②主运算函数

	//存储数值
	 private StoreStack numStack;
 	//存储运算符
 	private StoreStack synStack;

	//初始化
	 public Calculation() {
  		this.numStack = new StoreStack();
  		this.synStack = new StoreStack();
 	}
 	
	public double valueCalculate(String expression) {		
 		for(int loc = 0; loc < expression.length(); loc++) {
		//从运算式中取值
 		char c = expression.charAt(loc);
 	 	//①若该值为数字,再次取值,直至不为数字,然后将值拼起来,压入栈
	   	if(48<=c&&c<=57 || c == '.') {
 	  		int locate = 0; //判断是小数点前还是小数点后,且判断小数点后第几位
   			Double target = 0D;
   			while(48<=c&&c<=57 || c == '.') {
     				if(c == '.') {
   				locate = 1;
      				c = expression.charAt(++loc);
      				continue;
    			 }     
    			int a = c - 48;
  	   		if(locate == 0) {
      				target = a + target*10;  //转化为double类型
     			}else {
      				target += (double)a/Math.pow(10, locate);
      				//小数点位数加一
      				locate++;
    			}
   			 //取下一位
     			c = expression.charAt(++loc);       
    		 	}
  	  		this.numStack.push(target);  //入栈   
  		 }
		//②若为')',入栈
   		if(c == '(') {
   			 this.synStack.push(c);   
      		//③若为'+'或'-'
  		 }else if(c == '+' || c == '-') {
   			 if(!synStack.emptyStack() && !String.valueOf(synStack.catStackTop()).equals("(")) {
    			 //当运算符栈顶有值且不为括号时,进行运算
     			this.twoCalculate();
   		 } 
   		 //运算符入栈
    		synStack.push(c);
  		 //④若为'*'或'/'
  		 }else if(c == '*' || c == '/'){
   			 if(String.valueOf(synStack.catStackTop()).equals("(")
     				 || synStack.emptyStack()
     				 || String.valueOf(synStack.catStackTop()).equals("+")
     				 || String.valueOf(synStack.catStackTop()).equals("-")) {
      					//对于 +、-、空、(不做运算
    				}else {
    				 //对于 *、/ 调用运算器
    				 this.twoCalculate();
    				}      
    			//运算符入栈
    			synStack.push(c);
    		  //⑤若为')'
 	 	 }else if(c == ')') {
    			//查看栈顶运算符,循环计算括号中数值
   			 while(!String.valueOf(synStack.catStackTop()).equals("(")) {
     			//调用运算器
     				this.twoCalculate();
  		  	}
    			//取出括号'('
    			synStack.popStack(); 
  	 	//⑥a若为'='
  		 }else if(c == '=') {
    			//清空运算符,输出
  		  	while(!synStack.emptyStack()) {
     				this.twoCalculate();
  		 	 }	
	 	 } 
	}
  		 

③封装的运算函数

	private void twoCalculate() {  
  		//运算符和数字出栈
  		String sign = String.valueOf(synStack.popStack()); 
  
  		double a = Double.parseDouble(String.valueOf(numStack.popStack()));
  		double b = Double.parseDouble(String.valueOf(numStack.popStack()));
  
  		//为*、/时
  		if(sign.equals("*")) {
 			  numStack.push(b*a);
 		 }else if(sign.equals("/")) {
   			int mid = (int)(b/a*100);
   			//对于除法、取小数点后两位
  			 numStack.push((double)mid/100);
  		//为+、-时
 		 }else if(String.valueOf(synStack.catStackTop()).equals("-")) {     
  			 //若前一符号为负数、会影响加减运算,需判断
  			 if(sign.equals("+")) {
    				numStack.push(b-a);
  			 }else {
			     numStack.push(b+a);
   			}
 			 }else{
  				 if(sign.equals("+")) {
     					numStack.push(b+a);
				 }else {
   					  numStack.push(b-a);
  				 }
		  } 
    
	 }

运算结果
对于一级运算‘-’号影响的测试:
在这里插入图片描述
对于双括号,小数点前两位和后两位测试:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值