我发现了Internet上Shunting-yard算法的这种实现(Infix to Postfix with function support)
infix_to_postfix(infix):
postfix = []
infix.add(')')
stack = []
stack.push('(')
for each token in infix:
if token is operand:
postfix.add(token)
if token is '[':
stack.push(token)
else if token is operator:
if stack is empty OR
stack[top] is '(' or stack[top] is '[':
stack.push(token)
else if (operator)token['precedence'] > stack[top]['precedence'] OR
( (operator)token['precedence'] == stack[top]['precedence'] AND
(operator)token['associativity') == 'RIGHT' ):
stack.push(token)
else
postfix.add(stack.pop())
stack.push(token)
else if token is '(':
stack.push(token)
else if token is ')':
while topToken = stack.pop() NOT '(':
postfix.add(topToken)
else if token is ']':
while True:
topToken = stack.pop()
postfix.add(topToken)
if topToken is '[':
break
else if token is ',':
while topToken = stack.peek() NOT '[':
postfix.add(topToken)
stack.pop()
stack.push(token)
我尝试将其移植到C ++,但我不明白我在哪里错那是我的代码:
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
using namespace std;
string magic(string& infix){
const string ops = "-+/*%^";
string postfix;
stringstream ss;
stack<char> s;
string token;
infix+=")";
s.push('(');
for(int c = 0; c<infix.length(); ++c){
for(int op = 0; op<ops.length(); ++op){
if(infix[c] == ops[op])
postfix+=infix[c];
}
for (int op = 0; op<ops.length(); ++op){
if(infix[c]=='['){
s.push(infix[c]);
}else if(infix[c] == ops[op]){
if(s.empty() || s.top()=='(' || s.top()=='[')
s.push(infix[c]);
else if(0){
// cose con le precedenze
}else{
s.pop();
postfix+=s.top();
s.push(infix[c]);
}
}else if(infix[c]=='('){
s.push(infix[c]);
}else if(infix[c]==')'){
while(s.top() != '('){
s.pop();
char topc = s.top();
postfix += topc;
}
}else if(infix[c]==']'){
while(true){
s.pop();
char topc = s.top();
postfix+= topc;
if(topc == '[')
break;
}
}else if(infix[c]==','){
while(s.top()!='['){
char topc = s.top();
postfix += topc;
s.pop();
}
s.push(infix[c]);
}
}
}
return postfix;
}
int main() {
string infix = "[ sin ( 2 , 5 ) ] + 3 ^ ( 4 * ( 5 * ( 6 - 1 ) ) )";
cout << "infix: " << infix << '\n';
cout << "postfix: " << magic(infix) << '\n';
return 0;
}
如果您不能用C ++开发,我有什么替代方法?有做类似事情的算法更适合该问题吗?欢迎所有代码答案,谢谢。
您从该答案中转换代码时会遇到很多问题,其中包括答案中一个非常明显的错误,即第二个if
(if token is '['
)应该为else if
。但是请注意,第一个if
中的条件是if token is operand
,但是您的翻译大致是if token is operator
。这两个问题肯定足以阻止您的代码按需工作。
除此之外,重要的是要阅读引用答案中的注释,该注释指出伪代码基于已被标记化的输入;该代码不应直接应用于输入。特别是,数字和变量名称应该是令牌流中的单个元素。另外,请参见注释3,其中解释了[
和]
的来源;它们不在输入流中,因此必须由令牌发布者创建。
通常,在尝试编写实现时,特别是在移植的是伪代码时,尝试了解算法的工作原理很有帮助。 (有关伪代码的最重要的事情是,它不是代码,因此永远不会经过测试。即使是非常有经验的编码人员也很少注意到很小的错误,这些错误会误入伪代码。如果有一种运行伪代码的方法,这样的错误将被立即检测到,但是由于没有发现,因此在测试具体实现时会出现这些错误。总之,caveat receptor。]
the shunting-yard algorithm on Wikipedia有一个合理的解释。特别是,如果已知函数的名称,则Wikipedia页面上的伪代码将处理函数调用。
关于调车场的另一讨论,包括关于在标记输入时如何识别函数调用和一元运算符(前缀和后缀)的注释,请参见this answer on SO,其中还包括伪代码。
关于三个Shunting Yard演示文稿的一个有趣的事实是,它们各自具有将函数调用转换为后缀的样式。您需要解决的具体问题是后缀函数调用是模棱两可的,除非您以某种方式知道使用了多少个参数。 infix调用中的括号使参数计数显式,但是无括号的表示形式(如postfix)需要不同的机制。
使用逗号作为建立参数列表的二进制运算符,就像您尝试移植的代码一样,是一种有趣的策略。但是,所提供的伪代码无法处理没有参数的功能。 (此外,[
令牌还必须包含函数名称这一事实也没有得到很好的解释。)
另一方面,维基百科代码依赖于识别用作功能的标识符。并且它要求每个这样的函数都具有众所周知的参数数量。在计算器中这是可以的,其中的函数通常仅限于sin
和digamma
之类的东西,但是在通用编程语言中这是有问题的。
我的解决方案将CALL
运算符插入到后缀输出中;如注释所示,实际实现中还应该在CALL
之前插入提供的参数数量作为附加值。不过,实现细节还无法很好地解释。 (对不起!)