逆波兰表示法是一种是由波兰数学家扬·武卡谢维奇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 - * -