(详细注释)Java实现--表达式之中缀转后缀并计算

    自打遇到栈,一直都想些写一篇通俗易懂的将中缀表达式转化为后缀表达式的博文,今天总算完成了这个心愿。

    所有的解释在代码行里面均有解释。有什么不懂的可以在评论区或者私信我。

    为了不用一直拉动代码行看注释(这回很麻烦也很浪费时间),本人将较长的注释分成了两行。

写在前面:

      后缀表达式:波兰逆序数,将中缀表达式转换成后缀表达式不用做算数运算,它不求中缀表达式的值,只是把操作数和操作符重新排列成另一种形式:后缀表示法。然后再求后缀表达式的结果。在解析表达式的时候,我们是将运算操作符存放在一个栈里,*/的优先级要比+-高,但是如果+或者-在括号里面,那么它的优先级就要比* /要高。

定义栈代码:

(对栈还不够了解的,可以看我的另一篇博文)

https://blog.csdn.net/szlg510027010/article/details/82696158

  转换代码:

/**
 * 将中缀表达式转化为后缀表达式
 * @author Administrator
 *
 */
public class InToPost {
	private String input;
	private String output="";
	private StackX theStack;
	
	public InToPost(String in) {
		input = in;
		int stackSize = input.length();
		theStack = new StackX(stackSize);
	}
	
	public String doTrans() {
		//利用for循环,读取中缀表达式中的每一个字符
		for(int i=0;i<input.length();i++) {
		//定义一个字符型变量ch,将中缀表达式的字符赋给ch
			char ch = input.charAt(i);
		//演绎字符ch是否入栈,将栈中的内容先打印出来
			theStack.diaplayStack("For "+ch+" ");
		//利用switch-case语句,对应字符对应不同的操作
			switch(ch) {
			case '(':
		//如果ch是'('的话,直接将该字符压入栈中
				theStack.push(ch);
				break;
				
		//如果ch是')'的话,执行gotParen操作,Paren是parenthesis的缩写,
		//表示括号的意思,这里即要实现获取')'括号相对应的操作
			case ')':
				gotParen(ch);
				break;
		
		//如果ch是'+'或者'-'的话,获取操作Oper是Operation的缩写,即操作的意思
			case '+':
			case '-':
				gotOper(ch,1);
				break;
			
		//如果ch是'*'或者'/',执行gotOper方法
			case '*':
			case '/':
				gotOper(ch,2);
				break;
				
		//如果获取的字符既不是+-*/,也不是'('或者')',表示这个字符是数字,直接赋值给output.
			default:
				output+=ch;
				break;
		}
	}
	//当执行玩上述操作以后,栈不为空,则将栈中的元素一一赋值给output
	//什么时候执行完上述操作栈依然不为空呢?有很多例子,比如说(A+B)*C
	//在(A+B)*C中最后的时候栈中还会有*这个符号,因为我们在ch在==')'的时候
	//就把栈中里面的内容'+'和'('[注意这里是有顺序的,先执行'+']给执行了,在遇到'('的时候
	//直接pop,其实质是将top--,'('它本身还在数组里头,这在我们初步学习栈的时候就已经说明过了
	//此时top==-1.相当于栈是空的
	//遇到'*'以后,将其压入栈中
	//因为'*'后面已经没有其它操作符[+-*/)(],所以'*'就一直保存在栈中了
		while(!theStack.isEmpty()) {
			theStack.diaplayStack("While ");
			output+=theStack.pop();
		}
		theStack.diaplayStack("End ");
	//返回output,此时已经完成了将中缀表达式转化为后缀表达式
		return output;
}
	//当遇到'(''+''-'或者'*'/'的时候执行以下操作
	public void gotOper(char opThis,int prec1) {
	//只要栈中不为空,就要将栈顶元素拿出来,
	//若是'('则放回,若是'+''-''*''/'就要和栈顶元素进行比较
		while(!theStack.isEmpty()) {
	//获取栈顶元素
			char opTop = theStack.pop();
			
	//如果栈顶元素是'(',则将其放回栈中,因为有'(',
	//表示后面一定有运算操作是要先执行的,'('也可以是看做一个标志符,或者说是分割符
			if(opTop=='(') {
					theStack.push(opTop);
	//退出循环,继续下一个字符的操作
					break;
			}//否则如果不是'('的话,执行下面操作
			else {
	//定义一个prec2,prec2代表的是栈顶元素,
	//目的是为了跟prec1进行比较,prec1表示的是要插入栈中元素
	//如果prec2>prec1的话表示栈顶元素的优先级比要插入栈中的元素优先级要大,
	//此时我们就应该将栈顶元素赋值给output,比如栈顶元素opTop为'*'  opThis为'+'
	//如果prec2<prec1的话,表明栈顶元素的优先级要小于要插入栈中的优先级,
	//此时我们将opTop放回栈中,比如栈顶元素opTop为'+'  opThis为'*',刚好与上述情况相反
				int prec2;
				
				if(opTop=='+' || opTop=='-') {
					prec2 = 1;
				}else 
					prec2 = 2;	
				
				
				if(prec2<prec1) {
	//如果栈顶元素的优先级要小于要插入栈中的优先级,此时我们将opTop放回栈中
					theStack.push(opTop);
	//退出循环,继续下一个字符的操作
					break;
				}else
	//如果栈顶元素的优先级要大,则将其赋值给output
					output += opTop;
			}
		}
	//总结一下上述的操作,其实就是将栈顶元素取出来,然后考虑它是否应该放回到栈中,
	//放回栈中有两种情况:
	//1、如果遇到'(',我们就将它放回栈中
	//2、如果栈顶元素opTop的优先级要比opThis的优先级药效,我们将它(栈顶元素opTop)放回栈中
	//赋值给output的情况只有一种:
	//就是栈顶元素opTop的优先级要比opThis的要大,
	//此时我们直接将其赋值给output,
	//因为优先级都比opThis要大了,我们当然要先执行该运算啊!
		
	//考虑完栈顶元素opTop是应该放回还是不放回以后,我们将opThis放到栈里面去
		theStack.push(opThis);
		
		
	//注:此方法针对的符号是
	//'('		'+'		'-'		'*'		'/',五个,
	//如果遇到的是')',不执行该方法,执行的是下面的方法gotOparen
	}
	
	//如果遇到')'我们并不将')'压入栈中,这时候考虑的是是否将栈中元素赋值给output的问题了
	public void gotParen(char ch) { 
	//如果该栈不为空,为空的时候不可能(只要不是故意的)出现')',
	//因为在表达式里面有')'理所当然就有'('
	//所以不应该为空,为空根本就么有意义去讨论
	    while(!theStack.isEmpty()) {
	//获取栈顶元素,只要栈顶元素不是'(',
	//则我们将其赋值给output,然后进行下一次操作,直到遇到'('为止
		char chx = theStack.pop();
		if(chx=='(') {
			break;
		}else {
			output += chx;
		}
	}
	}
}

测试代码: 

/**
 * 测试转换
 * @author Administrator
 *
 */
public class TestTrans {
	public static void main(String[] args) {
		int interAns = 0;
		String input = "3*(4+5)-6/(1+2)";
		System.out.println("前缀表达式:"+input);
		InToPost test = new InToPost(input);
		String output = test.doTrans();
		System.out.println("后缀表达式:"+output);
		System.out.println("计算后缀表达式:--------");
		//定义一个新的栈,用于存放数字
		Stack2 newStack = new Stack2(output.length());
		//遍历output即后缀表达式,如果遇到数字则将其入栈
		//如果遇到的是操作符,则将紧挨操作符的前两个数字进行运算
		for(int i=0;i<output.length();i++) {
			//获取output中小标对应的字符
			char ch = output.charAt(i);
			//如果获取的元素是数字,那么将其用过相减转化为int类型
			//然后将其放到入栈
			if(ch>='0'&&ch<='9') {
				int number=ch-'0';
				newStack.push(number);
				System.out.println(newStack.peekTop());
			}else {
				//获取符号前面的两个数字
				//在这里一定要注意
				//num1和num2的顺序,+、*无所谓,但是-、/有所谓
				int num2 = newStack.pop();
				int num1 = newStack.pop();
				switch(ch) {
				case '+':
					interAns = num1 + num2;
					break;
				case '-':
					interAns = num1 - num2;
					break;
				case '*':
					interAns = num1 * num2;
					break;
				case '/':
					interAns = num1 / num2;
					break;
				}
				//讲运算的结果入栈,然后遍历下一个元素
				newStack.push(interAns); 
			}
		}
		//打印结果
		System.out.println("The Answer is:"+interAns);
	}
}

测试结果:

前缀表达式:D*(A+B)*C
For D Stack (bottom-->top):
For * Stack (bottom-->top):
For ( Stack (bottom-->top):* 
For A Stack (bottom-->top):* ( 
For + Stack (bottom-->top):* ( 
For B Stack (bottom-->top):* ( + 
For ) Stack (bottom-->top):* ( + 
For * Stack (bottom-->top):* 
For C Stack (bottom-->top):* 
While Stack (bottom-->top):* 
End Stack (bottom-->top):
后缀表达式:DAB+*C*

计算结果:

前缀表达式:3*(4+5)-6/(1+2)
后缀表达式:345+*612+/-
计算后缀表达式:--------
3
4
5
6
1
2
The Answer is:25

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
做一门精致,全面详细java数据结构与算法!!!让天下没有难学的数据结构,让天下没有难学的算法,不吹不黑,我们的讲师及其敬业,可以看到课程视频,课件,代码的录制撰写,都是在深夜,如此用心,其心可鉴,他不掉头发,谁掉头发???总之你知道的,不知道的,我们都讲,并且持续更新,走过路过,不要错过,不敢说是史上最全的课程,怕违反广告法,总而言之,言而总之,这门课你值得拥有,好吃不贵,对于你知识的渴求,我们管够管饱话不多说,牛不多吹,我们要讲的本门课程内容:稀疏数组、单向队列、环形队列、单向链表、双向链表、环形链表、约瑟夫问题、栈、前缀、中缀后缀表达式中缀表达式换为后缀表达式、递归与回溯、迷宫问题、八皇后问题、算法的时间复杂度、冒泡排序、选择排序、插入排序、快速排序、归并排序、希尔排序、基数排序(桶排序)、堆排序、排序速度分析、二分查找、插值查找、斐波那契查找、散列、哈希表、二叉树、二叉树与数组换、二叉排序树(BST)、AVL树、线索二叉树、赫夫曼树、赫夫曼编码、多路查找树(B树B+树和B*树)、图、图的DFS算法和BFS、程序员常用10大算法、二分查找算法(非递归)、分治算法、动态规划算法、KMP算法、贪心算法、普里姆算法、克鲁斯卡尔算法、迪杰斯特拉算法、弗洛伊德算法马踏棋盘算法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值