NYOJ 305 表达式求值
法一:
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //这个表达式求值,要先算最小单元的数值,可以采用递归方式 5 char str[350];//使用全局数据保存字符串 6 int first;//字符当前位置 7 int min(int x,int y) 8 { 9 return x>y ? y:x;//返回比较小的数 10 } 11 int max(int x,int y) 12 { 13 return x>y ? x:y;//返回比较大的数 14 } 15 int fun() //函数,分析字符 16 { 17 int v,n;//保存数字及数字的位数 18 switch(str[first]) //分析字符串的开头字符 19 { 20 case 'm': //有可能是max,min 21 first+=3;//指向 指向括号 22 if(str[first-2]=='i') //对于min 23 return min(fun(),fun()); //如min(3,5),递归时就会分别返回3和5,然后当成min的参数 24 else 25 return max(fun(),fun()); 26 break; 27 case 'a': //是add 28 first+=3; 29 return fun()+fun(); //如add(3,5),递归时就会返回3和5 30 break; 31 case ',': //分隔符 32 case '(': 33 case ')': 34 first++;//跳过不处理 35 return fun();//继续递归 36 break; 37 default: //数字 38 sscanf(str+first,"%d%n",&v,&n);//从字符str+first开始将数字读入v,数字位数为n,此处的%n含义是返回从调用开始到此读了多少个字节 39 first+=n;//走过数字 40 return v; 41 break; 42 } 43 } 44 int main() 45 { 46 int n,m; 47 scanf("%d",&n);//n组测试数据 48 while(n--) 49 { 50 scanf("%s",str);//字符数据 51 m=fun(); 52 printf("%d\n",m); 53 first=0;//每次测试完要使first归零 54 } 55 return 0; 56 }
法二:
1 #include<stdio.h> 2 char s[301],cstack[120]; 3 int dstack[80]; 4 int i,ctop,dtop; 5 int Operate(int a,char theta,int b) 6 { 7 switch(theta){ 8 case 'd': return a+b; 9 case 'n': return a>b?b:a; 10 case 'x': return a>b?a:b; 11 } 12 } 13 int EvaluateExpression() 14 { 15 char theta; 16 int a,b,k; 17 do{ 18 if(s[i]>'9'||s[i]<'0'){ 19 if(s[i]=='a'||s[i]=='m') i+=2; 20 if(s[i]==')'){ 21 --ctop; 22 theta=cstack[--ctop]; 23 a=dstack[--dtop]; 24 b=dstack[--dtop]; 25 dstack[dtop++]=Operate(a,theta,b); 26 }else if(s[i]!=',') cstack[ctop++]=s[i]; 27 ++i; 28 } 29 while(s[i]<='9'&&s[i]>='0'){ 30 for(k=0;s[i]!=','&&s[i]!=')'&&s[i]<='9'&&s[i]>='0';++i) 31 k=10*k+s[i]-'0'; 32 dstack[dtop++]=k; 33 if(s[i]==',') ++i; 34 } 35 }while(ctop); 36 return dstack[0]; 37 } 38 int main() 39 { 40 int N; 41 scanf("%d",&N); 42 while(N--){ 43 i=ctop=dtop=0; 44 scanf("%s",s); 45 printf("%d\n",EvaluateExpression()); 46 } 47 return 0; 48 }
解题思路:这是道表达式求值问题,只需考虑加法(add)、求最大值(max)以及最小值(min),可以用递归简单实现。注意括号和逗号的处理。
一道简单的模拟题,但是就是读入数据很麻烦,对于字符串的处理的能力还是太弱,以后得多练这类题目。。。。。
重新学习了一下sscanf的在字符串中读取正数的方法。
这道题用递归写会比较简单点。
1. C 语言中的输出函数printf中的%n格式的含义
可以将所输出字符串的长度值赋绐一个变量。
如下代码:
#include<stdio.h>
void main()
{
int slen;
printf("hello world%n", &slen);
printf("\n"); //换行
printf("%d",slen); //输出slen的值
printf("\n"); //换行
}
2. %n与其他格式说明符号不同。%n不向printf传递格式化信息,而是令printf把自己到该点已打出的字符总数放到相应变元指向的整形变量中。因此%n对于的变元必须是整形指针。
对printf调用返回之后,%n对于变元指向的变量中将包含有一个整数值,表示出现%n时已经由该次printf调用输出的字符数。
printf("this%n is a test\n",&count);//调用后count为4
3. sscanf的功能和scanf差不多,只是多了一个参数,该参数放于第一个,用来标识要被解析的字符串,相对于scanf来说,他其实就是你输入的字符串。懂了不
char szText[1024] = "123 34.4";
sscanf(szText, "%d %f", &a, &f);
a 就等于123,f就是34.4f
scanf 系列中有个函数 sscanf,可能有人用过,它的普通用法
gnu c 实现了 C 标准的 format specify 的 %n,它的含义是返回从该次 XXscanf 调用开始到此读了多少个字节,我们可以利用这一点,来实现不需要内存分配的%s:
4:switch的执行是按照从小到大的顺序执行的,最后执行default语句,如果default后面带有break,那么程序就会正常跳出switch,否则,程序会继续向后执行switch语句!也就是说,不管default放在什么位置,它总是在最后一个处理,然后继续向下处理!所以,最后的处理办法,避免出现以外结果的最好办法就是每一个case以及default语句都要加一个break!