分享几个代码
论坛里多是求代码、布作业的,大多数都不愿意通过看代码学习,所以我将最近练习的几个小代码不完整的分享下,所谓不完整,就是有几个地方需要填写几句简单代码,程序才能正常运行,希望籍此发动各位写代码的兴趣。一、递归方法完成带括号嵌套的整数四则混合运算
四则混合运算网上多是用栈方法完成的,还有什么用正则、用队列、用链表等等,看着头大。所以我自己琢磨了一个通过递归合并算式的方法完成。里面比较巧妙地通过在同一个字符串中分解为子串、递归将运算结果替代子串,最终得到运算结果,代码如下(代码中“//?”的行是需要补充的部分,一般都是简单的语句,填写对了,程序即可正常执行)
程序代码:/********************************
*可以括号嵌套的整数四则混合运算*
********************************/
#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编辑过]




很显然,你非常有IT精英的潜质!