分享几个代码
论坛里多是求代码、布作业的,大多数都不愿意通过看代码学习,所以我将最近练习的几个小代码不完整的分享下,所谓不完整,就是有几个地方需要填写几句简单代码,程序才能正常运行,希望籍此发动各位写代码的兴趣。一、递归方法完成带括号嵌套的整数四则混合运算
四则混合运算网上多是用栈方法完成的,还有什么用正则、用队列、用链表等等,看着头大。所以我自己琢磨了一个通过递归合并算式的方法完成。里面比较巧妙地通过在同一个字符串中分解为子串、递归将运算结果替代子串,最终得到运算结果,代码如下(代码中“//?”的行是需要补充的部分,一般都是简单的语句,填写对了,程序即可正常执行)
程序代码:
/******************************** *可以括号嵌套的整数四则混合运算* ********************************/ #include <stdio.h> int getnum(char *p,int *s) {//获取一个操作数 int i=*s,j=1,k; if(p[i]=='-') {//处理负数 i++; j=-1; } for(k=0;p[i]&&p[i]!='#'&&p[i]>='0'&&p[i]<='9';i++)k=k*10+p[i]-'0'; //数据字符串转换为整数 *s=i; return k*j; } int oper(char *p,char *op,int *s,int *e) { int i=0,j,num1=0,num2=0; *s=*e=-1; char c='+'; do { if(i)i++; *s=i; //返回该算式在字符串中起始位置 num1=getnum(p,&i); //? 这条语句稍微复杂点 ; //比较运算符 }while(i&&p[i]&&p[i]!='#'&&p[i]!=op[j]); //获取第一个操作数 if(p[i]&&p[i]!='#') { c=p[i]; //获取运算符 j=i+1; num2=getnum(p,&j); //获取第二个运算符 *e=j-1; //返回该算式在字符串中结束位置 } if(c=='+')num1+=num2; if(c=='-')num1-=num2; if(c=='*')num1*=num2; if(c=='/') { num2=num2?num2:1; //防止除0错误 num1/=num2; } if(c=='%') { num2=num2?num2:1; //防止除0错误 num1%=num2; } if(c=='^') { for(j=1;num2;num2--)j*=num1; //幂运算 num1=j; } return num1; //根据运算符对两个操作数做对应运算并返回运算结果 } int eval1(char *p) { int i,j,k,s,e; char b[3][10]={"^","*/%","+-"}; for(i=j=0;p[i];i++)if(p[i]!=' ')p[j++]=p[i];; //消算式中空格 p[j]=0; for(s=e=k=0;p[e]&&p[e]!='#'&&p[e]!=')';e++)if(p[e]=='(')s=e;; //左右扫描找到的第一个反括号一定是最内层的括号运算,同时s中是该反括号对应的正括号位置 if(p[e]&&p[e]!='#') {//有括号优先处理括号中的算式运算 p[s]=' '; p[e]='#'; //消除括号,把括号中算式当子串进行运算 k=eval1(p+s); //计算括号中的算式,结果在k中 for(e=s;p[e]!='#';e++); } else {//否则是不含括号的纯算式 for(i=0;i<3;i++) { k=oper(p,b[i],&s,&e); if(e>s)break; } //? ; //如果非算式(纯数字)则返回运算结果 } //计算结果回填到算式中替换原算式。结果在k中,回填位置为s、e之间 for(i=0;p[i];i++); for(;i>=e;i--)p[i+20]=p[i]; e+=20; //空出20个位置,插入运算结果,方便幂运算 p[s]=' '; if(k<0) { p[s]='-'; k=-k; //回填负数的处理,需要将该数转换为正整数填充 } for(i=e;i>s;i--)p[i]=' '; //首先将s-e之间填充空格 for(i=e;k&&i>s;k/=10)p[i--]=k%10+'0'; //其次将计算结果转换为数字字符填充 if(p[e]==' ')p[e]='0'; //如果全部空格,至少填充一个字符0 return eval1(p); //回填后的算式递归 } int eval(char *p) {//这个过渡函数的主要作用是复制字符串,防止出现调用者因实参为字符串常量不能修改的Bug int i,j; char a[500]; for(i=j=0;p[i];i++) if((p[i]>39&&p[i]<58&&p[i]!=44)||p[i]=='%'||p[i]=='^')a[j++]=p[i]; //拷贝并过滤非法字符(小数点未过滤) a[j]=0; return eval1(a); } void main() { printf("5-15*((6+3)/(-3)-3*2)/5=%d...测试括号嵌套\n",eval("5-15*((6+3)/(-3)-3*2)/5")); printf("-3*5+(3+2)*12=%d.............测试合法算式开头负号\n",eval("-3*5+(3+2)*12")); printf("-3+-*/15=%d..................测试运算符乱叠\n",eval("-3+-*/15")); printf("-3/a-b+15=%d.................测试非法字符\n",eval("-3/a-b+15")); printf("-3--123=%d..................测试负负得正\n",eval("-3--123")); printf("3^12-10 Mod 6*5=%d.......测试幂运算、模运算\n",eval("3^12-10%6*5")); printf("6*6 mod 4=%d 实际值=%d........测试模运算\n",eval("6*6%4"),6*6%4); printf("不是算式也可以有结果,懒得做算式合法检测函数了=%d\n",eval("不是算式也可以有结果,懒得做算式合法检测了")); }
程序运行结果:
5-15*((6+3)/(-3)-3*2)/5=32...测试括号嵌套
-3*5+(3+2)*12=45.............测试合法算式开头负号
-3+-*/15=-3..................测试运算符乱叠
-3/a-b+15=12.................测试非法字符
-3--123=120..................测试负负得正
3^12-10 Mod 6*5=531421.......测试幂运算、模运算
6*6 mod 4=0 实际值=0........测试模运算
不是算式也可以有结果,懒得做算式合法检测函数了=0
Press any key to continue
-3*5+(3+2)*12=45.............测试合法算式开头负号
-3+-*/15=-3..................测试运算符乱叠
-3/a-b+15=12.................测试非法字符
-3--123=120..................测试负负得正
3^12-10 Mod 6*5=531421.......测试幂运算、模运算
6*6 mod 4=0 实际值=0........测试模运算
不是算式也可以有结果,懒得做算式合法检测函数了=0
Press any key to continue
[此贴子已经被作者于2018-4-5 21:31编辑过]