算术中缀表达式转化成后缀表达式,并利用后缀表达式求值(操作数为个位数)

算术中缀表达式与后缀表达式

后缀表达式有利于计算机进行计算,中缀表达式有利于人们阅读与表达。

中缀表达式:a+b*c+(d*e+f)*g

对应的后缀表达式:abc*+de*f+g*+

将中缀表达式转化成后缀表达式

需要利用栈这种数据结构才能完成这一转化,在此用队列来存储后缀表达式:

中缀表达式的入栈规则:

1) 遇到操作数,直接输出到队列;

2)遇到操作符,输出到栈中,这个栈是一个操作符严格单调递增栈;(*,/ > +,-

3)遇到 '(' 左括号,直接输出到栈;

4)遇到 ')' 右括号,则将栈中的操作符都弹出到队列至'(' 左括号停止;

5)若读到中缀表达式末尾,将栈中所有操作符弹出至队列中;

	/**
	 * 将中缀表达式转化成后缀表达式并存储在队列中返回
	 * @param str
	 * @return 
	 */
	public static Queue infixToSuffix(String str) {
		Queue queue = new LinkedList();
		Stack stack = new Stack<>();//操作符优先级严格单调递增栈
		for(char c : str.toCharArray()) {
			if(c>='0' && c<='9') queue.offer(c);
			else if(c=='(') stack.push(c);
			else if(c==')') {
				char curOP=stack.pop();
				while(!stack.isEmpty() && curOP!='(') {
					queue.offer(curOP);
					curOP=stack.pop();
				}
			}
			else if(c>='*' && c<='/') {
				while(!stack.isEmpty() && stack.peek()!='(' && compare(c,stack.peek())==false) {
					queue.add(stack.pop());
				}
				stack.push(c);
			}
		}
		while(!stack.isEmpty()) queue.add(stack.pop());
		
		return queue;
	}
	
	/**
	 * 比较运算符的优先比大小
	 * @param a 当前字符
	 * @param b 从栈中弹出的字符
	 * @return
	 */
	public static boolean compare(char a,char b) {
		a = (char) (a=='*' ? a+5 : a);//将 '*' 转化成 '/',便于比较大小
		a = (char) (a=='+' ? a+2 : a);
		b = (char) (b=='*' ? b+5 : b);
		b = (char) (b=='+' ? b+2 : b);
		return a-b > 0;
	}

此处使用了一个小技巧来用于比较操作符优先级。

                                                                            +,-,*,/的ASCII码

* 74
+ 75
- 77
/ 79

由于该辅助栈是严格优先级单调递增栈,所以只需要比较 *,/ +,-不同级之间即可,同级必然要弹出,否则就无法构成严格单调递增栈。此处采用的方法是,将 * 平移到 / 处,将 + 平移到 - 处,再作比较即可。

	/**
	 * 比较运算符的优先比大小
	 * @param a 当前字符
	 * @param b 从栈中弹出的字符
	 * @return
	 */
	public static boolean compare(char a,char b) {
		a = (char) (a=='*' ? a+5 : a);//将 '*' 平移到 '/',便于比较大小
		a = (char) (a=='+' ? a+2 : a);
		b = (char) (b=='*' ? b+5 : b);
		b = (char) (b=='+' ? b+2 : b);
		return a-b > 0;
	}

利用后缀表达式求值

后缀表达式求值过程也需要栈的辅助,此处的栈为一般栈即可。

求值入栈规则:

1)遇到操作数,直接入栈;

2)遇到操作符,则将栈顶两个操作数取出计算,再将结果入栈;做减法与除法时特别要注意(第一个栈顶为第二操作数,第二栈顶才是第一操作数

3)最后将栈中最后的一个元素返回即为所求值;

	/**
	 * 
	 * @param queue 后缀表达式存储在此队列中
	 * @return 返回结果即为所求值
	 */
	public static int suffixToValue(Queue queue) {
		Stack stack = new Stack();
		while(!queue.isEmpty()) {
			char c = queue.poll();
			if(c>='0' && c<='9') stack.push(Integer.parseInt(c+""));
			else if(c>='*' && c<='/') {
				int b = stack.pop(); int a=stack.pop();// b为第二操作数,a为第一操作数
				stack.push(calculate(a,b,c));
			}
		}
		return stack.peek();
	}
	
	/**
	 * 
	 * @param a 第一操作数
	 * @param b 第二操作数
	 * @param c 操作符
	 * @return
	 */
	public static int calculate(int a,int b,char c) {
		int val=0;
		switch(c) {
		case('+'): val=a+b;break;
		case('-'): val=a-b;break;
		case('*'): val=a*b;break;
		case('/'): val=a/b;break;
		}
		return val;
	}

完整运行程序

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/**
 * 将算术表达式的中缀转换成后缀,只能处理0-9以内的运算
 * @author greatgeek
 *
 */
public class InfixtoSuffix {

	public static void main(String[] args) {
		String str="1+2*3+9/3+8-4+(5*6+7)*8";
		Queue queue = infixToSuffix(str);
		Character[] charArray = queue.toArray(new Character[queue.size()]);
		System.out.println(suffixToValue(queue));
		String res="";
		for(Character c : charArray) res += c;
		System.out.print(res);
	}
	
	/**
	 * 将中缀表达式转化成后缀表达式并存储在队列中返回
	 * @param str
	 * @return 
	 */
	public static Queue infixToSuffix(String str) {
		Queue queue = new LinkedList();
		Stack stack = new Stack<>();//操作符优先级严格单调递增栈
		for(char c : str.toCharArray()) {
			if(c>='0' && c<='9') queue.offer(c);
			else if(c=='(') stack.push(c);
			else if(c==')') {
				char curOP=stack.pop();
				while(!stack.isEmpty() && curOP!='(') {
					queue.offer(curOP);
					curOP=stack.pop();
				}
			}
			else if(c>='*' && c<='/') {
				while(!stack.isEmpty() && stack.peek()!='(' && compare(c,stack.peek())==false) {
					queue.add(stack.pop());
				}
				stack.push(c);
			}
		}
		while(!stack.isEmpty()) queue.add(stack.pop());
		
		return queue;
	}
	
	/**
	 * 比较运算符的优先比大小
	 * @param a 当前字符
	 * @param b 从栈中弹出的字符
	 * @return
	 */
	public static boolean compare(char a,char b) {
		a = (char) (a=='*' ? a+5 : a);//将 '*' 转化成 '/',便于比较大小
		a = (char) (a=='+' ? a+2 : a);
		b = (char) (b=='*' ? b+5 : b);
		b = (char) (b=='+' ? b+2 : b);
		return a-b > 0;
	}
	/**
	 * 
	 * @param queue 后缀表达式存储在此队列中
	 * @return 返回结果即为所求值
	 */
	public static int suffixToValue(Queue queue) {
		Stack stack = new Stack();
		while(!queue.isEmpty()) {
			char c = queue.poll();
			if(c>='0' && c<='9') stack.push(Integer.parseInt(c+""));
			else if(c>='*' && c<='/') {
				int b = stack.pop(); int a=stack.pop();// b为第二操作数,a为第一操作数
				stack.push(calculate(a,b,c));
			}
		}
		return stack.peek();
	}
	
	/**
	 * 
	 * @param a 第一操作数
	 * @param b 第二操作数
	 * @param c 操作符
	 * @return
	 */
	public static int calculate(int a,int b,char c) {
		int val=0;
		switch(c) {
		case('+'): val=a+b;break;
		case('-'): val=a-b;break;
		case('*'): val=a*b;break;
		case('/'): val=a/b;break;
		}
		return val;
	}

}

参考文章:

中缀表达式转换为后缀表达式

你可能感兴趣的:(数据结构与算法)