用什么样的算法可以实现这个功能(例如,给定一个字符串,如何找到答案):
((5 + (3 + (7 * 2))) - (8 * 9)) / 72
如果有人写了这样的东西,我该如何处理这么多嵌套的括号?
用什么样的算法可以实现这个功能(例如,给定一个字符串,如何找到答案):
((5 + (3 + (7 * 2))) - (8 * 9)) / 72
如果有人写了这样的东西,我该如何处理这么多嵌套的括号?
你可以使用逆波兰表达式或逆波兰式, 两者都使用栈来处理此问题,维基百科比我说得更好。
While there are tokens to be read:
Read a token.
If the token is a number, then add it to the output queue.
If the token is a function token, then push it onto the stack.
If the token is a function argument separator (e.g., a comma):
Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue. If no left parentheses are encountered, either the separator was misplaced or parentheses were mismatched.
If the token is an operator, o1, then:
while there is an operator token, o2, at the top of the stack, and
either o1 is left-associative and its precedence is less than or equal to that of o2,
or o1 is right-associative and its precedence is less than that of o2,
pop o2 off the stack, onto the output queue;
push o1 onto the stack.
If the token is a left parenthesis, then push it onto the stack.
If the token is a right parenthesis:
Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
Pop the left parenthesis from the stack, but not onto the output queue.
If the token at the top of the stack is a function token, pop it onto the output queue.
If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
When there are no more tokens to read:
While there are still operator tokens in the stack:
If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
Pop the operator onto the output queue.
Exit.
最简单的解决方法是实现Shunting Yard算法,将表达式从中缀表达式转换为后缀表达式。
评估后缀表达式非常容易。
Shunting Yard算法可以在不到30行代码的情况下实现。您还需要对输入进行标记化(将字符字符串转换为操作数、运算符和标点符号的序列),但编写一个简单的状态机来完成这项工作是直接的。
int y = string.IndexOf(")");
int x = string.Substring(0,y).LastIndexOf("(");
string z = string.Substring(x+1,y-x-1) // This should result in "7 * 2"
%option noyywrap
Number [0-9]+
WhiteSpace [ \t\v\r]+
NewLine \n
%{
#include <stdio.h>
%}
%%
\( return '(';
\) return ')';
\+ return '+';
\- return '-';
\* return '*';
\/ return '/';
{Number} return 'N';
{NewLine} return '\n';
{WhiteSpace} /* Ignore */
. fprintf(stdout,"Error\n");exit(1);
%%
%{
#include <stdio.h>
typedef double (*Operator)(double,double);
double mulOp(double l,double r) {return l*r;}
double divOp(double l,double r) {return l/r;}
double addOp(double l,double r) {return l+r;}
double subOp(double l,double r) {return l-r;}
extern char* yytext;
extern void yyerror(char const * msg);
%}
%union
{
Operator op;
double value;
}
%type <op> MultOp AddOp
%type <value> Expression MultExpr AddExpr BraceExpr
%%
Value: Expression '\n' { fprintf(stdout, "Result: %le\n", $1);return 0; }
Expression: AddExpr { $$ = $1;}
AddExpr: MultExpr { $$ = $1;}
| AddExpr AddOp MultExpr { $$ = ($2)($1, $3);}
MultExpr: BraceExpr { $$ = $1;}
| MultExpr MultOp BraceExpr { $$ = ($2)($1, $3);}
BraceExpr: '(' Expression ')' { $$ = $2;}
| 'N' { sscanf(yytext,"%le", &$$);}
MultOp: '*' { $$ = &mulOp;}
| '/' { $$ = &divOp;}
AddOp: '+' { $$ = &addOp;}
| '-' { $$ = &subOp;}
%%
void yyerror(char const * msg)
{
fprintf(stdout,"Error: %s", msg);
}
int main()
{
yyparse();
}
> flex e.l
> bison e.y
> gcc *.c
> ./a.out
((5 + (3 + (7 * 2))) - (8 * 9)) / 72
Result: -6.944444e-01
>
C语法
并提取所需部分)。> ./a.out
2 + 3 * 4
Result: 1.400000e+01
number
或者是这种形式
(expression operator expression)
这两种情况可以通过它们的第一个标记进行区分,因此简单的递归下降就足够了。实际上,我曾经看到过这个确切的问题被用作测试入门编程课程中递归思维的方法。
如果您不一定有这个保证,那么某种形式的优先级解析可能是一个好主意。这个问题的许多其他答案都讨论了各种算法的不同风味。
是的,算法是Shunting yard algorithm,但如果你想要实现它,我建议你使用Python和它的编译器包
import compiler
equation = "((5 + (3 + (7 * 2))) - (8 * 9)) / 72"
parsed = compiler.parse( equation )
print parsed
您还可以使用内置的eval()方法来评估此表达式
print eval("5 + (4./3) * 9") // 17
或者你可以在R中只用一行代码来完成这个操作:
> eval(parse(text = '((5 + (3 + (7*2))) - (8 * 9))/72' ))
[1] -0.6944444