算法实例练习记录——中序表达式转后续表达式问题(JAVA实现)

问题描述:将算术表达式由中序表达式转为后序表达式(目前仅限加减乘除)


 
 题目的核心还是利用Stack栈的特点——后进先出,解决问题,注意出栈规则——按照算术运算的优先级。
 中序表达式:方便人读取的算术表达式,如:1+2-2/(3-8)   ,类似这样的就是中序表达式了,其实就是我们日常中经常看到的算术表达式。
 后序表达式:方便计算机读取的算术表达式,如:12+238-/-  ,这个后序表达式就是上面的中序表达式的运算顺序了。

 


  程序的算法流程分析:
 1、准备两个栈,分别存储中序字符串中的 数字-->数字栈numsstack,符号-->符号栈opertstack,最终后序表达式结果存入——数字栈;
 2、从中序表达式中一个一个循环读取字符-->c,并对字符进行判定,取出的字符c,大致分四种情况:

         1)、c为数字(0-9)时,直接进入——数字栈numsstack;
         2)、c为符号-->运算符(+,-,*,/)时,要视以下几种情况,进行弹栈、压栈操作:
                a、如果符号栈opertstack此时为空,直接将c压入符号栈opertstack;
                b、如果符号栈opertstack不为空,弹出栈顶元素存入temp中:

                        i、如果temp为乘或者除(*或者/),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
                       ii、如果temp为加或者减(+或者-),此时要看c中的符号优先级:

                            *、如果c为加或者减(+或者-),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
                          **、如果c为乘或者除(*或者/),要看c在中序表达式中的前(pre)和后(next),是否分别为右括号(')'),和左括号('('):

                                @、是的话,temp和c都要压入符号栈opertstack;
                            @@、不是的话,c的优先级要高于temp,c压入数字栈numsstack,temp压入符号栈opertstack;
                      iii、如果temp为左括号(‘(’),将temp和c都压入符号栈opertstack中,等待右括号的到来;

        3)、c为符号-->右括号(‘)’)时,符号栈opertstack弹栈,并将弹出的栈顶元素加入数字栈numsstack,直至弹出的栈顶为(‘(’)左括号时,结束弹栈操作;
        4)、c为符号-->左括号(‘(’)时,将c直接压入符号栈opertstack中;

 3、中序表达式遍历结束后,如果符号栈opertstack里还有对象,就挨个出栈,压入数字栈numsstack

 


说实话,问题比我想象的要复杂,折腾了一天,终于整完了。测试了几组数据,目前看没啥大问题。

具体的实现都在程序中了。 

 

import java.util.Stack;

//将算术表达式由中序表达式转为后序表达式
/*
 * 题目的核心还是利用Stack栈的特点——后进先出,解决问题。
 * 中序表达式:方便人读取的算术表达式,如:1+2-2/(3-8)   ,类似这样的就是中序表达式了,其实就是我们日常中经常看到的算术表达式。
 * 后序表达式:方便计算机读取的算术表达式,如:12+238-/-  ,这个后序表达式就是上面的中序表达式的运算顺序了。
 */

/*
 * 程序的算法流程分析:
 * 1、准备两个栈,分别存储中序字符串中的 数字-->数字栈numsstack,符号-->符号栈opertstack,最终后序表达式结果存入——数字栈;
 * 2、从中序表达式中一个一个循环读取字符-->c,并对字符进行判定,取出的字符c,大致分四种情况:
 * 		1)、c为数字(0-9)时,直接进入——数字栈numsstack;
 *		2)、c为符号-->运算符(+,-,*,/)时,要视以下几种情况,进行弹栈、压栈操作:
 *				a、如果符号栈opertstack此时为空,直接将c压入符号栈opertstack;
 *				b、如果符号栈opertstack不为空,弹出栈顶元素存入temp中:
 *						i、如果temp为乘或者除(*或者/),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
 *					   ii、如果temp为加或者减(+或者-),此时要看c中的符号优先级:
 *							*、如果c为加或者减(+或者-),c的优先级低于temp,所以,temp压入数字栈numsstack,c压入符号栈opertstack;
 *						  **、如果c为乘或者除(*或者/),要看c在中序表达式中的前(pre)和后(next),是否分别为右括号(')'),和左括号('('):
 *								@、是的话,temp和c都要压入符号栈opertstack;
 *							@@、不是的话,c的优先级要高于temp,c压入数字栈numsstack,temp压入符号栈opertstack;
 *					  iii、如果temp为左括号(‘(’),将temp和c都压入符号栈opertstack中,等待右括号的到来;
 *		3)、c为符号-->右括号(‘)’)时,符号栈opertstack弹栈,并将弹出的栈顶元素加入数字栈numsstack,直至弹出的栈顶为(‘(’)左括号时,结束弹栈操作;
 *		4)、c为符号-->左括号(‘(’)时,将c直接压入符号栈opertstack中;
 *3、中序表达式遍历结束后,如果符号栈opertstack里还有对象,就挨个出栈,压入数字栈numsstack。
 */

public class MidExpressTransLastExpress {

	//两个栈分别存储中序表达式中的数字和符号
	//numsstack-->存储数字的栈,也是最终的后序表达式的结果栈。
	//opertstack-->存储运算符等符号的栈。
	private static Stack<Character> numsstack=new Stack<Character>();
	private static Stack<Character> opertstack=new Stack<Character>();
	
	//具体的转换方法
	public static void transMidToLast(String str) {
		
		//存储最终的后序表达式的字符串
		String target=new String();
		//中序字符串中,当前位置--->i 位置的字符c
		char c;
		// i位置的前一个字符
		char next=0;
		// i位置的后一个字符
		char pre=0;
		//比较用的临时字符存储空间
		char temp = 0;
		
		//程序的主要交换逻辑,一个for循环,将中序表达式从头到尾遍历一遍。
		for(int i=0; i<str.length(); i++) {
			c=str.charAt(i);
			if(i<str.length()-1) next=str.charAt(i+1);
			if(i>0) pre=str.charAt(i-1);
			
			//根据获取的当前位置 i ,来进行分支选择。
			switch(c) {
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					numsstack.push(c);//c为数字时,进入数字栈
					break;
				
				// c为加减乘除时,进行的选择操作
				case '+':
				case '-':
				case '*':
				case '/':
					if(opertstack.isEmpty()) opertstack.push(c);//符号栈为空的话,符号c直接进栈。
					else temp=opertstack.pop();//否则弹出符号栈的栈顶元素,存入临时空间temp中。
					if(temp=='*' || temp=='/') {//符号栈的栈顶为乘除时,直接将这个栈顶元素压入数字栈,当前符号压入符号栈。
						numsstack.push(temp);
						opertstack.push(c);
					}
					if(temp=='+' || temp=='-' ) {//符号栈栈顶为加减时,要分两个情况,一个是c为乘除,一个是c为加减。
						if(c=='*' || c=='/') {//c 为乘除时,要看当前c在中序表达式中的前(next)后(pre),是否为左括号和右括号,两种情况。
							if(next=='(' || pre==')') {//c的前后为左右括号时,要将temp和c,按顺序压入字符栈。
								opertstack.push(temp);
								opertstack.push(c);	
							}else {//c的前后不是左右括号时,temp如字符栈,c入数字栈。
								opertstack.push(temp);
								numsstack.push(c);
							}
						}
						if(c=='+' || c=='-') {//c为加减时,temp如数字栈,c如字符栈。
							numsstack.push(temp);
							opertstack.push(c);
						}
					}
					if(temp=='(') {//符号栈的栈顶元素为左括号时,符号栈重新压入取出的栈顶,然后再压入c。
						opertstack.push(temp);
						opertstack.push(c);
					}
					break;
					
				case ')'://c为右括号时,字符栈的栈顶要出栈,同时压入数字栈,直到字符栈出栈的栈顶元素为左括号为止。
					temp=opertstack.pop();
					while(temp!='(' && !opertstack.isEmpty()) {
						numsstack.push(temp);
						temp=opertstack.pop();
					}
					temp=0;
					break;
					
				case '('://c为左括号,无条件直接压入字符栈。
					opertstack.push(c);
					break;
					
				default:
					break;
			}
		}
		
		//中序表达式,遍历结束后,如果字符栈里还有符号,直接出栈,压入数字栈中。
		while(!opertstack.isEmpty()) {
			temp=opertstack.pop();
			if(temp!='(') numsstack.push(temp);
		}
		System.out.println(numsstack.toString());
		
		//数字栈开始出栈,一个一个加入target字符串中。
		while(!numsstack.isEmpty()) {
			target=numsstack.pop().toString()+target;
		}
		
		System.out.println(target);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		transMidToLast("(1-2)*4+(91+2)");
		transMidToLast("(5+1)*2-3*(2*(1-3))");
		transMidToLast("(5+1)*2-2*((1-3)*2)/2");
	}

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值