简介
中缀表示法(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)。与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被电脑解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
目的
将中缀表达式(即标准的表达式)转换为后缀表达式
例如:1+2*3+(4*5+6)*7 转换成 123*+45*6+7*+
转换原则:
当读到一个操作数时,立即将它放到输出中。操作符不立即输出,放入栈中。遇到圆括号也是推入栈中。
如果遇到一个右括号,那么就将栈元素弹出,将符号写出直到遇到一个对应的左括号。但是这个左括号只被弹出,并不输出。
在读到操作符时,如果此时栈顶操作符优先级大于或等于此操作符,弹出栈顶操作符直到发现优先级更低的元素位置。除了处理‘)’的时候,否则决不从栈中移走‘(’。操作符中,‘+’和‘-’优先级最低,‘*’和‘/’优先级中等,‘(’和‘)’最高。
如果读到输入的末尾,将栈元素弹出直到该栈为空,将符号写到输出中。
实例
首先,读入‘1’,并送到输出,然后‘+’被读入并压入栈中。接下来‘2’读入并送到输出,此时状态如下:
栈:+
输出:1 2
接下来读入‘*’,由于优先级比栈顶元素‘+’大(原则3),因此被压入栈中,接着读入‘3’,并送到输出:
栈:+ *
输出:1 2 3
然后读入‘+’,由于此时栈顶元素为‘*’,优先级比‘+’大,因此将‘*’弹出,弹出后原来的‘+’变为栈顶元素,由于‘+’的优先级和当前读入的‘+’优先级相等,因此也被弹出(原则3),最后将读入的‘+’压入栈中,因此状态如下:
栈:+
输出:1 2 3 * +
下一个读入的符号‘(’,由于具有最高优先级,因此将其放入栈中,然后读入‘4’:
栈:+ (
输出: 1 2 3 * + 4
继续读入,此时读入‘*’,除非处理‘)’,否则‘(’绝不会弹出,因此‘*’被压入栈中,接下来读入‘5’:
栈:+ (*
输出:1 2 3 * + 4 5
往后读入的符号是‘+’,将‘*’弹出并输出。然后将‘+’压入栈中,接着读入‘6’:
栈:+ ( +
输出:1 2 3 * + 4 5 * 6
现在读入‘)’,因此弹出栈中元素直到遇到‘(’:
栈:+
输出:1 2 3 * + 4 5 * 6 +
下一个有读入‘*’,被压入栈中,然后读入‘7’:
栈:+ *
输出:1 2 3 * + 4 5 * 6 + 7
现在输入为空,弹出所有栈中元素
栈:空
输出:1 2 3 * + 4 5 * 6 + 7 * +
实现代码
/*
利用栈将(中缀表达式)转换成(后缀表达式)
e.g.
1+2*3+(4*5+6)*7 转换成 123*+45*6+7*+
infix(中缀表达式) : 1+2*3+(4*5+6)*7
postfix(后缀表达式) : 123*+45*6+7*+
*/
#include <iostream>
#include <string>
#include <stack>
#include <map>
using namespace std;
void InfixToPostfix(const string infix, string& postfix)
{
stack<char> mark; // 符号栈
std::map<char, int> priority; // 符号优先级
priority['+'] = 0;
priority['-'] = 0;
priority['*'] = 1;
priority['/'] = 1;
int infix_length = infix.size(); // 中缀表达式的字符长度
postfix.reserve(infix_length);
for(int i = 0; i < infix_length; ++i) {
switch(infix[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
postfix.push_back(infix[i]);
break;
case '+':
case '-':
case '*':
case '/':
if(!mark.empty()) {
char markTop = mark.top();
while(markTop != '(' && priority[infix[i]] <= priority[markTop]) {
postfix.push_back(markTop);
mark.pop();
if(mark.empty()) {
break;
}
markTop = mark.top();
}
}
mark.push(infix[i]);
break;
case '(':
if(infix[i - 1] >= '0' && infix[i - 1] <= '9') { // 5(6/2-1) <==> 5*(6/2-1)
mark.push('*');
}
mark.push(infix[i]);
break;
case ')':
{
char markTop = mark.top();
while(markTop != '(') {
postfix.push_back(markTop);
mark.pop();
markTop = mark.top();
}
mark.pop();
}
break;
default:
break;
}
}
// 剩余的全部出栈
while(!mark.empty()) {
postfix.push_back(mark.top());
mark.pop();
}
}
int main(int argc, char const *argv[])
{
std::string infix = "1+2*3+(4*5+6)*7+(1+2)";
std::string postfix;
cout << "infix : " << infix << endl;
InfixToPostfix(infix, postfix);
cout << "postfix : " << postfix << endl;
return 0;
}