本文将继续扩展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;
}
二、 “ Postfix2Infix ”
它的原理于上面的相似,只是在调整顺序的时候,保证“算符在算子中间,并添加圆括号”。
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;
}
注:类似的原理,也可以处理“prefix expression”。
三、“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;
}
}
注:从该函数对圆括号的成对处理方法,可以扩展:在处理C++代码时,由于代码块是用花括号包裹,而花括号也是成对出现的,也可以采用栈进行缓存处理。或者,更简单的办法是“计算”。设定“int count = 0”;遇到左花括号则“++count”;遇到右花括号则“--count”;