用堆栈实现“中缀表达式”转“后缀表达式”

逆波兰表示法是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。逆波兰表达式的解释器一般是基于堆栈的。
例如表达“三加四”时,写作“3 4 +”,而不是“3 + 4”。如果有多个操作符,操作符置于第二个操作数的后面,所以常规中缀记法的“3 - 4 + 5”在逆波兰记法中写作“3 4 - 5 +”:先3减去4,再加上5。



用堆栈实现“中缀表达式”转“后缀表达式”的思路:

定义后缀表达式字符数组,依次遍历中缀表达式,若是数字,直接保存到字符数组中,若是字符,第一个字符直接入栈,后面
   的字符入栈的原则是:若栈顶的字符优先级高于栈外字符,则栈顶字符先出栈保存到字符数组中,然后栈外字符再入栈;若
   栈顶字符优先级低于栈外字符,则栈外字符直接入栈。优先级的判断规则是:
   
	·相同等级的运算符,栈内高于栈外
	·栈外的左括号优先级最高
	·栈内的左括号优先级最低
	·栈外的右括号优先级最低,和栈内的左括号优先级一样
	
	等到中缀表达式完全遍历完以后,说明此时所有的数字都已保存到字符数组中,然后再去将栈中的字符依次出栈保存到字
	符数组中,转换完成。

看以下程序:

1、先定义优先级的判断类

class Constant {

	public static final int OPERATORS_PRIO_PLUS_IN = 4;  //栈内加法
	public static final int OPERATORS_PRIO_SUB_IN  =  4;   //栈内减法
	public static final int OPERATORS_PRIO_MULTY_IN  =  2; //栈内乘法
	public static final int OPERATORS_PRIO_DIV_IN  =  2 ;  //栈内除法
	public static final int OPERATORS_PRIO_LEFT_BRAK_IN  =  10;  //栈内左括号

	public static final int OPERATORS_PRIO_PLUS_OUT  =  5 ; //栈外加法
	public static final int OPERATORS_PRIO_SUB_OUT  =   5;   //栈外减法
	public static final int OPERATORS_PRIO_MULTY_OUT  =  3; //栈外乘法
	public static final int OPERATORS_PRIO_DIV_OUT  =  3;   //栈外除法
	public static final int OPERATORS_PRIO_LEFT_BRAK_OUT =  1;  //栈外左括号
	public static final int OPERATORS_PRIO_RIGHT_BRAK_OUT =  10;  //栈外右括号
	public static final int OPERATORS_PRIO_ERROR = -1;
	
}

2、转换程序:

public class Demo {
	
	/** 用于判断字符的优先级 */
	public static int Get_Prio(char opera,boolean instack)
	{
		int prio = Constant.OPERATORS_PRIO_ERROR;
		// 表示栈内字符,对应true
		if(instack)
		{
			switch(opera)
			{
			case '+':
				prio = Constant.OPERATORS_PRIO_PLUS_IN;
				break;
			case '-':
				prio = Constant.OPERATORS_PRIO_SUB_IN;
				break;
			case '*':
				prio = Constant.OPERATORS_PRIO_MULTY_IN;
				break;
			case '/':
				prio = Constant.OPERATORS_PRIO_DIV_IN;
				break;
			case '(':
				prio = Constant.OPERATORS_PRIO_LEFT_BRAK_IN;
				break;
			default:
				prio = Constant.OPERATORS_PRIO_ERROR;
				break;
			}
		}
		// 表示栈外字符,对应false
		else
		{
			switch(opera)
			{
			case '+':
				prio = Constant.OPERATORS_PRIO_PLUS_OUT;
				break;
			case '-':
				prio = Constant.OPERATORS_PRIO_SUB_OUT;
				break;
			case '*':
				prio = Constant.OPERATORS_PRIO_MULTY_OUT;
				break;
			case '/':
				prio = Constant.OPERATORS_PRIO_DIV_OUT;
				break;
			case '(':
				prio = Constant.OPERATORS_PRIO_LEFT_BRAK_OUT;
				break;
			case ')':
				prio = Constant.OPERATORS_PRIO_RIGHT_BRAK_OUT;
				break;
			default:
				prio = Constant.OPERATORS_PRIO_ERROR;
				break;
			}
		}
		return prio;
	}
	
	public static void strMidToLast(String strMid,char[] strLast) {
		
		char[] stack = new char[strMid.length()];
		int top = 0;
		int len = strMid.length();
		// 用于遍历中缀表达式
		int i = 0;
		// 用于strLast[]的下标
		int j = 0;
		// 表示栈内优先级
		int prioIn;
		// 表示栈外优先级
		int prioOut;
		
		while (i != len) {
			// 判断是否是数字,若是数字直接存储到后缀表达式数组中,i和j后移一位
			if(Character.isDigit(strMid.charAt(i))) {
				strLast[j++] = strMid.charAt(i);
				i++;
			// 是字符的情况
			}else {
				// 若栈内没有元素,字符直接入栈,i后移一位,top上移一位
				if (top == 0) {
					stack[top++] = strMid.charAt(i);
					i++;
				// 栈内有元素的情况
				}else {
					// 用true与false表示是栈内还是栈外
					prioIn = Get_Prio(stack[top - 1],true);
					prioOut = Get_Prio(strMid.charAt(i), false);
					// 若栈内优先级高,栈内元素出栈,保存到后缀表达式数组,j后移一位,top下移一位
					if(prioIn < prioOut) {
						strLast[j++] = stack[--top];
					// 遇到括号的情况,直接出栈,i后移一位,忽略括号
					}else if(prioIn == prioOut) {
						top--;
						i++;
					// 若栈外优先级高,直接入栈,i后移一位,top上移一位
					}else {
						stack[top++] = strMid.charAt(i);
						i++;
					}
				}
			}
		}
		/* while表达式执行完毕,则中缀表达式遍历完毕,此时若栈内还有元素,
		 * 直接出栈,每次j后移一位,top下移一位,直到栈为空
		 */
		while(top > 0) {
			strLast[j++] = stack[--top];
		}
	}
	
	/** 后缀表达式的输出 */
	public static void print(char[] strLast) {
		for (int x = 0; x < strLast.length; x++) {
			System.out.print(strLast[x] + " ");
		}
		System.out.println();
	}
}

验证一下以上程序:

	public static void main(String[] args) {
		String strMid = "2+3*5-4*(5-3)";
		char[] strLast = new char[strMid.length()];
		strMidToLast(strMid, strLast);
		print(strLast);
	}

结果是:

		2 3 5 * + 4 5 3 - * -
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值