数据结构的Java实现(六)—— 前缀、中缀、后缀表达式

什么是前缀表达式,中缀表达式,后缀表达式?

以 3+4-5为例:

  1. 前缀表达式:操作符在操作数的前面,即 -+345
  2. 中缀表达式:操作符在操作数的中间,即 3+4-5
  3. 后缀表达式:操作符在操作数的后面,即 34+5-

为什么计算机对前缀 / 后缀表达式比较方便?

前缀 / 后缀表达式中不存在括号,通过前缀 / 后缀表达式可以很容易构造一颗运算树,通过该运算树,可以使用递归的方式很方便计算表达式。


将中缀表达式转为前/后缀表达式的简单转换方法:

设中缀表达式为 a + b * c - ( d + e )

step1:【加括号】为每一步运算加括号,即为 ( ( a + ( b * c ) ) - ( d + e ) )

step2:【移符号】将每一步括号内的运算符移动到该括号外

                                  前缀表达式:- ( + ( a * ( b c ) ) + ( d e ) )

                                  后缀表达式:( ( a ( b c ) * ) + ( d e ) + ) -

step3:【去括号】将表达式内所有括号移除

                                  前缀表达式:- + a * b c + d e

                                  后缀表达式:a b c * + d e + -


中缀表达式转后缀表达式

  1. 初始化两个栈,一个是操作符栈s1,一个是操作数栈s2;
  2. 从左至右遍历中缀表达式;
  3. 当为操作数时,直接压入s2;
  4. 当为( 时,直接压入s1;
  5. 当为 )时,将s1栈顶弹出并压入s2,直至遇到(,并舍弃该对括号;
  6. 当为操作符时,如果s1为空 或 s1栈顶为( 或 当前操作符优先级大于栈顶,直接压入s1;
  7. 当为操作符时,如果s1不为空且s1栈顶不为( 且当前操作符优先级不大于栈顶,将s1栈顶弹出并压入s2,直至满足6;
  8. 重复2-7,直至遍历完中缀表达式;
  9. 将s1内元素弹出压入s2;
  10. 弹出s2,逆序即为后缀表达式。
package yrwan05;

public class InfixToSuffix {

	/**
	 * 将中缀表达式转为后缀表达式
	 * 
	 * @param in 传入中缀表达式
	 * @return 后缀表达式
	 */
	public static CharStack change(String in) {
		CharStack s1 = new CharStack(in.length());// 操作符栈
		CharStack s2 = new CharStack(in.length());// 操作数栈
		// 开始判断
		for (int i = 0; i < in.length(); i++) {
			System.out.print("s1栈元素为(栈底--->栈顶):");
			s1.display();
			System.out.print("s2栈元素为(栈底--->栈顶):");
			s2.display();
			char ch = in.charAt(i);
			System.out.println("当前待判断的字符:" + ch);
			if ((ch <= '9' && ch >= '0') || (ch <= 'z' && ch >= 'a')) {// 遇到数压入s2
				s2.push(ch);
			} else if (ch == '(') {// 遇到左括号,直接压入s1
				s1.push(ch);
			} else if (ch == ')') {// 遇到右括号,将s1弹出并压入s2,直至s1遇到左括号,并舍弃这对括号
				char temp;
				while ((temp = s1.pop()) != '(') {
					s2.push(temp);
				}
			} else {// 遇到运算符
				// 若s1非空 并且 s1的栈顶不是"(" 并且 ch优先级不大于s1的栈顶
				while (!s1.isEmpty() && s1.peek() != '(' && !compare(ch, s1.peek())) {
					s2.push(s1.pop());// 将s1弹到s2,直至满足下方条件
				}
				// 若s1为空 或 s1的栈顶是"(" 或 ch优先级大于s1的栈顶
				s1.push(ch);
			}
		}
		// 中缀表达式遍历完成,将s1的元素弹到s2
		while (!s1.isEmpty()) {
			s2.push(s1.pop());
		}
		return s2;
	}

	/**
	 * 比较两运算符优先级
	 * 
	 * @param a 传入待比较
	 * @param b 传入栈顶
	 * @return true是a大,false是a小或相等
	 */
	public static boolean compare(char a, char b) {
		if ((a == '*' || a == '/') && (b != '*' || b != '/')) {
			return true;
		} else {
			return false;
		}
	}
}

中缀表达式转前缀表达式

  1. 初始化两个栈,一个是操作符栈s1,一个是操作数栈s2;
  2. 从右至左遍历中缀表达式;
  3. 当为操作数时,直接压入s2;
  4. 当为 )时,直接压入s1;
  5. 当为( 时,将s1栈顶弹出并压入s2,直至遇到 ),并舍弃该对括号;
  6. 当为操作符时,如果s1为空 或 s1栈顶为)或 当前操作符优先级大于等于栈顶,直接压入s1;
  7. 当为操作符时,如果s1不为空且s1栈顶不为) 且当前操作符优先级小于栈顶,将s1栈顶弹出并压入s2,直至满足6;
  8. 重复2-7,直至遍历完中缀表达式;
  9. 将s1内元素弹出压入s2;
  10. 弹出s2,即为前缀表达式。
package yrwan05;

public class InfixToPrefix {

	/**
	 * 将中缀表达式转为前缀表达式
	 * 
	 * @param in 传入中缀表达式
	 * @return 前缀表达式
	 */
	public static CharStack change(String in) {
		CharStack s1 = new CharStack(in.length());// 操作符栈
		CharStack s2 = new CharStack(in.length());// 操作数栈
		// 开始判断
		for (int i = in.length() - 1; i >= 0; i--) {
			System.out.print("s1栈元素为(栈底--->栈顶):");
			s1.display();
			System.out.print("s2栈元素为(栈底--->栈顶):");
			s2.display();
			char ch = in.charAt(i);
			System.out.println("当前待判断的字符:" + ch);
			if ((ch <= '9' && ch >= '0') || (ch <= 'z' && ch >= 'a')) {// 遇到数压入s2
				s2.push(ch);
			} else if (ch == ')') {// 遇到右括号,直接压入s1
				s1.push(ch);
			} else if (ch == '(') {// 遇到左括号,将s1弹出并压入s2,直至s1遇到右括号,并舍弃这对括号
				char temp;
				while ((temp = s1.pop()) != ')') {
					s2.push(temp);
				}
			} else {// 遇到运算符
				// 若s1非空 并且 s1的栈顶不是")" 并且 ch优先级小于s1的栈顶
				while (!s1.isEmpty() && s1.peek() != ')' && compare(s1.peek(), ch)) {
					s2.push(s1.pop());// 将s1弹到s2,直至满足下方条件
				}
				// 若s1为空 或 s1的栈顶是")" 或 ch优先级大于等于s1的栈顶
				s1.push(ch);
			}
		}
		// 中缀表达式遍历完成,将s1剩余的元素弹到s2
		while (!s1.isEmpty()) {
			s2.push(s1.pop());
		}
		while (!s2.isEmpty()) {
			s1.push(s2.pop());
		}
		return s1;
	}

	/**
	 * 比较两运算符优先级
	 * 
	 * @param a 传入待比较
	 * @param b 传入栈顶
	 * @return true是a大,false是a小或相等
	 */
	public static boolean compare(char a, char b) {
		if ((a == '*' || a == '/') && (b != '*' || b != '/')) {
			return true;
		} else {
			return false;
		}
	}
}

CharStack类为:

package yrwan05;

/**
 * 用于存放运算符与运算数的栈
 * @author Wyran
 *
 */
public class CharStack {
	private char[] arr;
	private int top;

	public CharStack(int size) {
		arr = new char[size];
		top = -1;
	}

	public void push(char c) {
		if (!isFull()) {
			arr[++top] = c;
		}
	}

	public char pop() {
		return arr[top--];
	}

	public char peek() {
		return arr[top];
	}

	public boolean isEmpty() {
		return top == -1;
	}

	public boolean isFull() {
		return top == arr.length - 1;
	}

	// 为了便于后面分解展示栈中的内容,增加了一个遍历栈的方法
	public void display() {
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}
}

测试类为:

package yrwan05;

import java.util.Scanner;

public class ITStest {
	public static void main(String[] args) {
		CharStack result;
		System.out.print("输入中缀表达式:");
		Scanner sc = new Scanner(System.in);
		String input = sc.nextLine();
		result =InfixToSuffix.change(input);// 转为后缀表达式
		System.out.print("\n转换后的后缀表达式为:");
		result.display();
		System.out.println("-----------------------------------");
		result = InfixToPrefix.change(input);// 转为前缀表达式
		System.out.print("\n转换后的前缀表达式为:");
		result.display();
		sc.close();
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值