本文将继续扩展Stack在Arithmetical Expression的处理方面的应用,其中包括:“Postfix2Prefix”、“Postfix2Infix”和“Infix2Postfix”。
一、“Postfix2Prefix”
它是通过多次入栈和出栈来完成的。主要步骤是:遍历“postfix string”:
1)是算子先压栈;
2)是算符就先取出它需要的算子,调整顺序(保证算符在前,算子在后),并焊接在一个整体(string),再压栈。
bool IsOperator(char c) { if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^') return true; else return false; } void Postfix2Prefix(string & postfix, string & prefix) { // convert the input postfix expression to prefix format StackAsLinkedList stack; for (unsigned int i = 0; i < postfix.length(); ++i) //process each char in the postfix string from left to right { string s{ postfix[i] }; if (std::isdigit(postfix[i])) stack.Push(*new String(s)); else if (IsOperator(postfix[i])) { String & arg2 = dynamic_cast<String&>(stack.Pop()); String & arg1 = dynamic_cast<String&>(stack.Pop()); stack.Push(*new String(s + string(arg1) + string(arg2))); delete &arg1; delete &arg2; } } String & arg = dynamic_cast<String&>(stack.Pop()); prefix = string(arg); delete & arg; }
它的原理于上面的相似,只是在调整顺序的时候,保证“算符在算子中间,并添加圆括号”。
void Postfix2Infix(string & postfix, string & infix) { // convert the input postfix expression to infix format StackAsLinkedList stack; for (unsigned int i = 0; i < postfix.length(); ++i) //process each char in the postfix string from left to right { string s{ postfix[i] }; if (std::isdigit(postfix[i])) stack.Push(*new String(s)); else if (IsOperator(postfix[i])) { String & arg2 = dynamic_cast<String&>(stack.Pop()); String & arg1 = dynamic_cast<String&>(stack.Pop()); stack.Push(*new String(string("(") + string(arg1) + s + string(arg2) + string(")"))); delete &arg1; delete &arg2; } } String & arg = dynamic_cast<String&>(stack.Pop()); infix = string(arg); delete & arg; }
三、“Infix2Postfix”
它的原理要稍微复杂一些。需要比较运算符的优先级和考虑运算符的结合性以及圆括号。它也是遍历“infix string”:
1)遇到数字,直接append到“postfix string”;
2)遇到算符,与栈顶的算符比较优先级,如果栈顶算符优先级高,则将栈顶算符append到“postfix string”,反复进行比较,知道遇到圆括号,或者栈顶算符优先级更低为止,最后将新算符压栈(这样,栈内的算符优先级是从低到高顺序排序);
3)遇到左括号压栈,遇到右括号出栈。(对于括号是成对处理)
int GetOperatorWeight(char op) { int weight = -1; switch (op) { case '+': case '-': weight = 1; break; case '*': case '/': weight = 2; break; case '^': weight = 3; break; } return weight; } bool IsRightAssociative(char op) { if (op == '^') return true; else return false; } bool HasHigherPrecendence(char lOperator, char rOperator) { int op1Weight = GetOperatorWeight(lOperator); int op2Weight = GetOperatorWeight(rOperator); // If operators have equal precedence, return true if they are left associative. // return false, if right associative. // if operator is left-associative, left one should be given priority. if (op1Weight == op2Weight) { if (IsRightAssociative(lOperator)) return false; else return true; } return op1Weight > op2Weight ? true : false; } void Infix2Postfix(string & infix, string & postfix) { // convert the input infix expression to postfix format StackAsLinkedList stack; for (unsigned int i = 0; i < infix.length(); ++i) //process each char in the postfix string from left to right { string s{ infix[i] }; if (infix[i] == ' ' || infix[i] == ',') // If character is a delimitter, move on. continue; else if (std::isdigit(infix[i])) postfix += infix[i]; else if (IsOperator(infix[i])) // If character is operator { while (!stack.IsEmpty() && string(dynamic_cast<String&>(stack.Top())) != string("(") && HasHigherPrecendence(string(dynamic_cast<String&>(stack.Top()))[0], infix[i])) // operators in stack ordered by precedence { String & arg = dynamic_cast<String&>(stack.Pop()); postfix += string(arg); delete &arg; } stack.Push(*new String(string{ infix[i] })); } else if (infix[i] == '(') { stack.Push(*new String(string{ infix[i] })); } else if (infix[i] == ')') // a pair of parenthesis is a processing unit { while (string(dynamic_cast<String&>(stack.Top())) != string("(")) { String & arg = dynamic_cast<String&>(stack.Pop()); postfix += string(arg); delete &arg; } stack.Pop(); } } while (!stack.IsEmpty()) { String & arg = dynamic_cast<String&>(stack.Pop()); postfix += string(arg); delete &arg; } }