【实用擂台】实时计算表达式(字符串)的值!!!!

littlecpu 2003-08-26 01:38:43
引:JavaScript和PB中有一种内建函数可以实时计算字符串表达式,本檑台就是想把这个功能引伸成通用解法,可以各语言中建立对应的功能函数自如使用。

题:对于由 + - * / ^ 五种二元数值运算符,左右括号,数值组成的格式规范的运算表达式,计算出其最终结果!优先度为 () > ^ > */ > + -

例:1+2 结果为 3
例: 1/0 结果为 NaN或指出除0错误
例:1 - (2 * 4) ^ 2 结果为 -63
例:2 * (4 - (2 -2) 指出错误(表达式格式不正确)

这个题绝对实用!期待有心者的精彩解答,请使用主流语言作答。代码外请另加约十行的思路说明!!!代码间有注释的大大欢迎!!!

本人分不少(5000+),参与者皆送分,答案确有实用价值的都100分(类同者先帖者100,后帖皆参与分),功能正确都200分!有突破性解法的300分

约二至三周后结帖,请帮忙多Up,免得沉到海底了!

谢谢积极参与!
...全文
47 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
Sunnyiez 2003-10-14
  • 打赏
  • 举报
回复
http://www.hfutbbs.net/active/forum/dispbbs.asp?boardID=34&ID=30795
Heskey 2003-10-14
  • 打赏
  • 举报
回复
//@**#---2002-08-01 17:53:52 (Heskey)---#**@

/* -----------------------------基本思路---------------------------
本程序计算由+,-,*,/,^ ,() 组成的四则运算,基本思路是压栈!
1、设一个符号栈,一个数字栈,每次碰到优先级更高的符号就继续压,否则计算。
2、关于如何结束,可以在表达式末加一个特殊符号(如=),把它的优先级设为最低即可。
3、关于括号,可以见到一个'('使一个int变量加10,碰')'减,对于每一个括号内的符号,使其优先级加上刚才那个int数,这样,就可以当没有括号了。
------------------------------------------------------------------- */

#include <fstream>
#include <cmath>
#include <stack>
using namespace std;

ifstream fin("calc.in");
ofstream fout("calc.out");

int prior(char op);
double calc(double a,double b,char op);
double run();

int main(int argc, char* argv[])
{
int n;
fin>>n;
for(int i=0;i<n;i++)
{
fin.ignore(1000,'\n');
fout<<run()<<endl;
}
return 0;
}

double calc(double a,double b,char op)
{
switch(op)
{
case '+': return a+b;
case '-': return a-b;
case '*': return a*b;
case '/': return a/b;
case '^': return pow(a,b);
}
return -1;
}

int prior(char op)
{
if(op=='+' || op=='-')
return 2;
else if(op=='*' || op=='/')
return 3;
else if(op=='^')
return 4;
else
return 1;
}

double run()
{
char ch;
int extra=0; //优先级修正!
bool trueMinus=false; //'-'当...为真时是减号!
stack<double> fig;
stack<char> oper;
stack<int> pri; //与oper对应的优先级!
oper.push('$');
pri.push(0);

do
{
fin>>ch;
switch(ch)
{
case '+':
case '-': if(trueMinus==false)
fig.push(0);
case '*':
case '/':
case '^':
case '=': while(prior(ch)+extra <= pri.top())
{
double right=fig.top();
fig.pop();
double left=fig.top();
fig.pop();
char op=oper.top();
oper.pop();
pri.pop();
fig.push(calc(left,right,op));
}
oper.push(ch);
trueMinus=false;
pri.push(prior(ch)+extra);
break;
case '(': extra+=8; continue;
case ')': extra-=8; continue;
default: fin.putback(ch);
double temp;
fin>>temp;
fig.push(temp);
trueMinus=true;
}
}while(ch!='=');
return fig.top();
}

/* ----------------------------输入输出样例------------------------------------
输入文件要求: 第一行一个整数n,说明表达式的总数,后面n行是n个表达式,
必须以 '=' 结束。
输入:
4
(3*(5-2)^2-4*(-8+5*(4-4^0.5)))/2-4*.3=
-(-4*(-(6-3)))+(-.5)=
(((((5-2.5)/5)^2+0.75)^39+4*4^0.5)^0.5-45/9*0.3)^2+1=
-7*(-8+9)-(-1)^9-(-.5)=
输出:
8.3
-12.5
3.25
-5.5
-------------------------------------------------------------------------- */
zhoukun666 2003-10-14
  • 打赏
  • 举报
回复
/* 修改: LaughCry2002 2002-7-16 10:44 */

/* 用栈实现表达式求值: Defines the entry point for the console application. */



#include <stdio.h>

#include <stdlib.h>

#include <string.h>



#define DEBUG



#define NULL 0

#define ERROR -1

#define STACKSIZE 20



/* 定义字符类型栈 */

typedef struct{

char stackname[20];

char *base;

char *top;

} Stack;



/* ----------------- 全局变量--------------- */

Stack OPTR, OPND; /* 定义前个运算符栈,后个操作数栈 */

char expr[255] = ""; /* 存放表达式串 */

char *ptr = expr;

int step = 0; /* 计算的步次 */



int InitStack(Stack *s, char *name)

{

s->base=(char *)malloc(STACKSIZE*sizeof(char));

if(!s->base) exit (ERROR);

strcpy(s->stackname, name);

s->top=s->base;

return 1;

}



int In(char ch)

{

return(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#');

}



void OutputStatus(void)

{

char *s;



/* step */

printf("\n%-8d", ++step);



/* OPTR */

for(s = OPTR.base; s < OPTR.top; s++)

printf("%c", *s);

printf("\t");



/* OPND */

for(s = OPND.base; s < OPND.top; s++)

printf("%d ", *s);



/* input char */

printf("\t\t%c", *ptr);

}



int Push(Stack *s,char ch)

{

#ifdef DEBUG

char *name = s->stackname;

OutputStatus();

if(strcmp(name, "OPND") == 0)

printf("\tPUSH(%s, %d)", name, ch);

else

printf("\tPUSH(%s, %c)", name, ch);

#endif

*s->top=ch;

s->top++;

return 0;

}



char Pop(Stack *s)

{

char p;

#ifdef DEBUG

OutputStatus();

printf("\tPOP(%s)", s->stackname);

#endif

s->top--;

p=*s->top;

return (p);

}



char GetTop(Stack s)

{

char p=*(s.top-1);

return (p);

}



/* 判断运算符优先权,返回优行权高的 */

char Precede(char c1,char c2)

{

int i=0,j=0;

static char array[49]={ '>', '>', '<', '<', '<', '>', '>',

'>', '>', '<', '<', '<', '>', '>',

'>', '>', '>', '>', '<', '>', '>',

'>', '>', '>', '>', '<', '>', '>',

'<', '<', '<', '<', '<', '=', '!',

'>', '>', '>', '>', '!', '>', '>',

'<', '<', '<', '<', '<', '!', '='};



switch(c1)

{

/* i为下面array的横标 */

case '+' : i=0;break;

case '-' : i=1;break;

case '*' : i=2;break;

case '/' : i=3;break;

case '(' : i=4;break;

case ')' : i=5;break;

case '#' : i=6;break;

}

switch(c2)

{

/* j为下面array的纵标 */

case '+' : j=0;break;

case '-' : j=1;break;

case '*' : j=2;break;

case '/' : j=3;break;

case '(' : j=4;break;

case ')' : j=5;break;

case '#' : j=6;break;

}

return (array[7*i+j]); /* 返回运算符 */

}



/*操作函数 */

Operate(int a,char op,int b)

{

#ifdef DEBUG

OutputStatus();

printf("\tOPERATE(%d, %c, %d)", a, op, b);

#endif



switch(op)

{

case '+' : return (a+b);

case '-' : return (a-b);

case '*' : return (a*b);

case '/' : return (a/b);

}

return 0;

}



int EvalExpr(void)

{

char c,theta,x,m,ch;

int a,b;



c = *ptr++;

while(c!='#'||GetTop(OPTR)!='#')

if(!In(c))

{

m=atoi(&c);

Push(&OPND,m);

c = *ptr++;

}

else

switch(Precede(GetTop(OPTR),c))

{

case '<':

Push(&OPTR,c);

c = *ptr++;

break;

case '=':

x=Pop(&OPTR);

c = *ptr++;

break;

case '>':

theta=Pop(&OPTR);

b=Pop(&OPND); a=Pop(&OPND);

Push(&OPND,Operate(a,theta,b));

break;

}



return GetTop(OPND);

}





int main(void)

{

/*

printf("Input the expression(end with \"#\" sign):");

do{

gets(expr);

}while(!*expr);

*/

strcpy(expr, "3*(7-2)#");



InitStack(&OPTR, "OPTR"); /* 初始化运算符栈 */

Push(&OPTR,'#'); /* 将#压入运算符栈 */

InitStack(&OPND, "OPND"); /* 初始化操作数栈 */



printf("\n\nresult:%d\n", EvalExpr());



return 0;

}



zhoukun666 2003-10-14
  • 打赏
  • 举报
回复
礼尚往来,我还是来贴一个
zhoukun666 2003-10-14
  • 打赏
  • 举报
回复
up--收藏,,呵呵!
sliant 2003-10-13
  • 打赏
  • 举报
回复
用java实现的
词法分析用的正则表达式,j2se 1.4.1新添的,自带的正则表达式包
语法分析用switch-case简单的弄了一下
http://www.csdn.net/develop/read_article.asp?id=20719
http://www.ch2000.com.cn/~ganxc/expression.zip
apogeecsj 2003-10-12
  • 打赏
  • 举报
回复
/* Compute expressions
*----------------------running---------------------*/
#include "stdafx.h"
#include <iostream>
#include <stack>
#include <queue>
#include <string>
#include <cmath>

using namespace std;

queue< char > qexp; //store postorder expression
queue< double > qdata; // store datas
stack< char > sop; //additional stack for postorder
stack< double > result; //used when compute,store results


/*----------get operation prioty-----------------*/
int get_prioty( char op ) {
switch( op ) {
case '(': return 1000;
case '+': case '-': return 3;
case '*': case '/': case '%':return 2;
case '^': return 1;
case ')': return 0;
default: cerr << "Unknow operation! when get_prioty" << endl; exit(1);
}
}

/*-------------get datas from expressions-------------*/
void get_op_data( const string& expr ) {
int i = 0;
int c_op = 0; //current op prioty
int t_op = 0; // top op stack prioty
int lenth = expr.length();
double data = 0;
for( ; i < lenth; i++ )
{
if( isdigit( expr[i] ) )
{
data = atof( &expr[i] );
qdata.push( data );
qexp.push( 'D' ); //D marks it's data,for the queue type is char
//cannot store data
for( ;( (isdigit( expr[i] ) || (expr[i] == '.'))&&(i<lenth) ); i++ );
}

switch( expr[i] )
{
case '(': sop.push( expr[i] ); break;
case '+': case'-': case '*': case '/': case'%': case '^':
c_op = get_prioty( expr[i] );
while( !sop.empty() ) {
t_op = get_prioty( sop.top() );
if( c_op < t_op ) break;
else {
qexp.push( sop.top() );
sop.pop();
}
}
sop.push( expr[i] );
break;
case ')':
while( !sop.empty() ) {
if( sop.top() == '(' )
{
sop.pop();
break;
}
else {
qexp.push( sop.top() );
sop.pop();
}
}
break;
}//switch

}//for
while( !sop.empty() ) { // add the op from sop to opstack
qexp.push( sop.top() );
sop.pop();
}
}
/* -----data and op from stack: sdata ,opstack, to compute result ----*/

int compute() {
char mark;
int data = 0;
int a = 0;
int b = 0;
while( !qexp.empty() ) {
mark = qexp.front();
qexp.pop();
if( mark == 'D' )
{
data = qdata.front();
qdata.pop();
result.push( data );
}
else {
switch( mark )
{
case '+':
a = result.top();
result.pop();
b = result.top();
result.pop();
result.push( b+a );
break;
case '-':
a = result.top();
result.pop();
b = result.top();
result.pop();
result.push( b-a );
break;
case '*':
a = result.top();
result.pop();
b = result.top();
result.pop();
result.push( b*a );
break;
case '/':
a = result.top();
result.pop();
b = result.top();
result.pop();
result.push( b/a );
break;
case '%':
a = result.top();
result.pop();
b = result.top();
result.pop();
result.push( b%a );
break;
case '^':
a = result.top();
result.pop();
b = result.top();
result.pop();
result.push( pow(b,a) );
break;
}//switch
}//else
}//while
return result.top();
}

int main(int argc, char* argv[])
{
string expr;
cout << "Please enter a expression to be compute:" << endl;
cin >> expr;
get_op_data( expr );
int result = compute();
cout << "Result: " << result << endl;
return 0;
}
WYlslrt 2003-09-09
  • 打赏
  • 举报
回复
用到编译原理了呵呵。
littlecpu 2003-09-08
  • 打赏
  • 举报
回复
不想结,再顶
寻开心 2003-08-26
  • 打赏
  • 举报
回复
那你就参考,前段时间斑竹搞的那个24点的运算程序,里面原理说的清楚。
代码还是c的。
littlecpu 2003-08-26
  • 打赏
  • 举报
回复
你知我不懂C++的,Go On Baby!!!


继续ing...
寻开心 2003-08-26
  • 打赏
  • 举报
回复
表达式算式解析器,CSDN早公布源代码啦。
到这里看:http://www.csdn.net/cnshare/soft/4/4589.shtm
影子传说 2003-08-26
  • 打赏
  • 举报
回复
up
littlecpu 2003-08-26
  • 打赏
  • 举报
回复
good, mark
freebird1020 2003-08-26
  • 打赏
  • 举报
回复
思路(1):
1。词法分析
2、语法分析:根据下面的文法
Expression -> SimpleExpression [RelOp SimpleExpression]...
SimpleExpression -> ['+' | '-'] Term [AddOp Term]...
Term -> Factor [MulOp Factor]...
Factor -> Designator ['(' ExprList ')']
-> Number
-> String
-> '(' Expression ')'
-> TypeId '(' Expression ')'RelOp -> '>'
。。。可以采用底归下降底分析方法,在语法分析过程中构造出一颗二叉树
其节点数据结构定义:
type
pTreeNode=^TTreeNode;
TTreeNode=record
Val : Double; // 节点的值
operator:string[20]; // 操作符
IdName:string[20]; // 标识符的值
NodeType:ExpKind; // 结点类型
Lchild:pTreeNode; // 左孩子节点
Rchild:pTreeNode; // 右孩子节点
end;
方法定义:
function NewExpNode(kind:expkind):pTreeNode;//生成表达式的结点 function function ExprList:pTreeNode;
function Exp:pTreeNode;
function Simple_exp:pTreeNode;
function Term:pTreeNode;
function Factor:pTreeNode;
function match(excepted:tokentype):boolean
procedure ClearTree(var Tree:pTreeNode);overload;
function ComputerTree(Tree:pTreeNode; var ParamList:string):double;
3:进行计算,通过后续遍历这颗二叉树进行计算
我现在做的这个表达式计算,可以支持自定义函数,并且支持不定参数的计算,如sum(a,b...任意多个),而且表达式里面也可以嵌套表达式,如sum(a,sum(a,b,c))+4/5。。。
这种思路最关键的是要在内存中构造出一颗二叉树,通过递归调用,计算出表达式的值。
function TParserTree.ComputerTree(Tree:pTreeNode;var ParamList:string):Double; //后续计算表达式的值;
var
ret1,ret2:double;
arr:mytype;
i:integer;
ret:double;
begin
if Tree<>nil then
begin
ret1:=ComputerTree(Tree^.Lchild,Paramlist);
ret2:=ComputerTree(Tree^.Rchild,ParamList);
case Tree.NodeType of
opk : begin
//showmessage(tree.operator);
if tree.operator='+' then result:=ret1+ret2
else if tree.operator='-' then result:=ret1-ret2
else if tree.operator='*' then result:=ret2*ret1
else if tree.operator='/' then
if ret2<>0 then
result:=ret1/ret2
else
begin
showmessage('div by zero');
result:=0;
exit;
end
else if tree.operator='' then
begin
ParamList:=ParamList+' '+floattostr(ret1)+' '+floattostr(ret2);
result:=0;
end
else if tree.operator='sum'then
begin
//showmessage(paramlist);
if paramlist<>'' then
begin
if tree.Lchild.operator ParamList:=ParamList+' '+floattostr(ret1);
....
constk : begin
result:=tree.Val;
//showmessage(floattostr(tree.val));
end;
思路2:
类似思路1:
1)词法分析
2)语法分析,构造语法树(实际为二叉树)
3)后续遍历语法树,得到表达式的逆波兰表达式
4)通过一遍扫描,计算后续表达式的值
付:计算后续表达式的算法:
function read(Expression:string;var idx:integer):string;
var
ret:string;
begin
ret:='';
if idx<=length(Expression) then
begin
while (Expression[idx]<>' ' )and (idx<=length(Expression))do
begin
ret:=ret+Expression[idx];
inc(idx);
end;
end;
inc(idx);//使Idx指向非空元素;
if Expression[idx]=' 'then
inc(idx); //两个空格表示当前字符是参数之一;
result:=ret;
end;


function sum(a,b:double):double;//自定义函数
begin
result:=a+b;
end;

function square(x:double):double;//自定义函数
begin
result:=x*x;
end;

function Multy(a,b,c:double):double;
begin
result:=a-c+b;
end;

procedure Computer_Expression(Expression:string);
var
idx:integer;
Op:string;//从字符串中读取的元素;
op1,op2,op3,ret:Double;
stk:TStackCls;
cRet:string;
begin
idx:=1;
stk:=TStackCls.Create;
while idx<=length(Expression)do
begin
op:=read(trim(Expression),idx);
if trim(op)='+' then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
ret:=op1+op2;
stk.push(floattostr(ret));
end
else if trim(op)='-' then
begin
op1:=strtofloat(stk.pop); // Pop(S)弹出减数
op2:=strtofloat(stk.pop); //Pop(S)弹出的是被减数
ret:=op2-op1;
stk.push(floattostr(ret));
end
else if trim(op)='*' then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
ret:=op1*op2;
stk.push(floattostr(ret));
end
else if trim(op)='/' then
begin
op1:=strtofloat(stk.pop); // Pop(S)弹出除数
if(op1<>0.0)then
ret:=strtofloat(stk.pop)/op1 //Pop(S)弹出的是被除数
else //除数为0时终止运行
begin
showmessage('div by zero');
exit;
end;
stk.push(floattostr(ret));
end
else if trim(op)='sum'then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
ret:=sum(op1,op2);
stk.push(floattostr(ret));
end
else if trim(op)='square'then
begin
op1:=strtofloat(stk.pop);
ret:=square(op1);
stk.push(floattostr(ret));
end
else if trim(op)='multy'then
begin
op1:=strtofloat(stk.pop);
op2:=strtofloat(stk.pop);
op3:=strtofloat(stk.pop);
ret:=multy(op3,op2,op1);
stk.push(floattostr(ret));
end
else
begin
stk.push(op);
end;
end;
if not stk.IsEmpty then
cRet:=stk.pop;
if not stk.IsEmpty then
begin
showmessage('参数数目不匹配,请重新输入!!!');
end
else
showmessage('计算结果='+cRet);
stk.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var pp:TparserTree;
str:string;
begin
pp:=tparserTree.create;
str:='sum(9,sum(3,4))+(8*9+888)+(9-(4))*3/8+((5-(8)))';
pp.Atoken.Origin:=pchar(str);
form2.Memo1.Clear;
form2.Memo2.Clear;
form2.Memo3.Clear;
form2.Memo1.Lines.Add(str);
pp.SyntaxTreeShow;
form2.ShowModal;
Computer_Expression(pp.postExpression);
pp.Free;
end;

两种思想对比:
思路一较思路二
效率高,在后续遍历的过程中就进行计算,
支持不定数目参数的自定义函数,
出错处理比较容易
支持表达式嵌套
思路二,计算方法比较容易,只能支持固定数目的自定义函数,支持表达式嵌套
这方面的计算还要一种比较经典的思路:算法优先算法,比较简单就不多说了。


littlecpu 2003-08-26
  • 打赏
  • 举报
回复
哈哈哈哈

不过,大伙有空还是练练手的好。这个题源自当时我做一个纺织业纺纱智能设计项目得来的需求!当时是用PB的函数实现的。现在觉得这个有用处,所以邀大家一起共同烟酒一下!
寻开心 2003-08-26
  • 打赏
  • 举报
回复
HEHE.
这个楼主不是斑竹吧。
frankzch 2003-08-26
  • 打赏
  • 举报
回复
怎么老是表达式求值一类的题目啊,能不能有点新意?
vanluns 2003-08-26
  • 打赏
  • 举报
回复
明白说的是什么,用堆栈的方法应该可以实现。
懒的很,不原动脑子。就来蹭点分。
UP一下。
^&^
boodweb 2003-08-26
  • 打赏
  • 举报
回复
楼主看看编译原理的递归下降分析,很快就会自己写了

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧