逆波兰计算器 进阶版(可以直接计算中缀表达式,支持 小数,负数)

    科技2026-02-27  7

    2020年 4-27号 ,我发表了这篇文章,

    然后之前的这 篇文章的代码并不支持 小数,负数,然后于今天 21点07分 我把这个问题解决了(不是从四月份开始解决的,是因为 之前上网课没时间弄,然后这个学期学数据结构,所以就搞一波,也没有看网上的博客,全都是自己一个人解决的 俺觉得 挺骄傲 的d=====( ̄▽ ̄*)b) 直接上代码!

    #include<iostream> #include<cstring> #include<math.h> #include<ctype.h>//isdigit()头文件 #include<stdlib.h> #define add_size 20 //顺序栈的实现: using namespace std; class seqstack_d { double *top; double *base; int stacksize; public : void inistack2(seqstack_d *s); void push2(seqstack_d *s,double e); void pop2(seqstack_d *s, double *e); int stacklength2(); } ; int seqstack_d::stacklength2() { return this->top-this->base; } void seqstack_d::pop2(seqstack_d *s ,double *e) { if(s->top==s->base)//如果栈为空,就return return; //如果栈不为空,就弹数据出来; *e=*--(s->top);//出栈,栈顶下移,因为栈顶不存数据 所以是-- 后 取值 } void seqstack_d::inistack2( seqstack_d *s ) { s->base =(double *) malloc (sizeof (add_size *sizeof(double ) ));//为栈分配20个char 长度的空间大小; if(!s->base)//如果base 是null 的话,分配内存失败,base指向一个空的指针,然后就要退出; exit(0); //否则就是成功分配内存 s->top=s->base; s->stacksize=add_size; } void seqstack_d::push2(seqstack_d *s ,double e ) { if(s->top-s->base>=s->stacksize)//应该不会出现大于的情况,只会出现等于的情况,即栈满了的情况,此时要分配额外的内存给指针 //否则会报错 { s->base = (double *)realloc (s->base,s->stacksize+add_size); if(!s->base) exit(0); s->stacksize=s->stacksize+add_size; //s->top=s->base+s->stacksize;//这行代码好像有问题 } //如果没有超出栈的空间大小,那么照常运行。 *(s->top)=e; s->top++; } class seqstack { char *top; char *base; int stacksize; public : void inistack(seqstack *s); void push(seqstack *s,char e); void pop(seqstack *s, char *e); int stacklength(); } ; int seqstack::stacklength() { return this->top-this->base; } void seqstack::pop(seqstack *s ,char *e) { if(s->top==s->base)//如果栈为空,就return return; //如果栈不为空,就弹数据出来; *e=*--(s->top);//出栈,栈顶下移,因为栈顶不存数据 所以是-- 后 取值 } void seqstack::inistack( seqstack *s ) { s->base =(char *) malloc (sizeof (add_size *sizeof(char ) ));//为栈分配20个char 长度的空间大小; if(!s->base)//如果base 是null 的话,分配内存失败,base指向一个空的指针,然后就要退出; exit(0); //否则就是成功分配内存 s->top=s->base; s->stacksize=add_size; } void seqstack::push(seqstack *s ,char e ) { if(s->top-s->base>=s->stacksize)//应该不会出现大于的情况,只会出现等于的情况,即栈满了的情况,此时要分配额外的内存给指针 //否则会报错 { s->base = (char*)realloc (s->base,s->stacksize+add_size); if(!s->base) exit(0); s->stacksize=s->stacksize+add_size; //s->top=s->base+s->stacksize;//这行代码好像有问题 } //如果没有超出栈的空间大小,那么照常运行。 *(s->top)=e; s->top++; } int main() { //开辟一个char 类型的数组 用来记录这个逆波兰表达式 char store [150] ; int x=0; //这个x用来记录 逆波兰表达式 的所有字符的长度; seqstack l;//定义一个顺序栈 char c, e ;//两个char 类型变量,一个用来记录输入,一个用来存储; l.inistack(&l); cout<<"请输入中缀表达式 ,以#作为结束标志(支持小数、负数,如果要输入负数 请按照以下格式输入: '(-1)*2+3#' : \n"; cin>>c; char store2[150]; int i=0; while(c!='#') { store[i++]=c; cin>>c; } store[i]='\0'; int k=0; for(int j = 0; j <=i;j++)//由于我们要计算负数嘛, 所以我们要对字符串进行处理一下 例如:(-1) 变成(0-1) { if(store[j]!='(') { store2[j]=store[k]; k++; } if (store[j]=='('&& store[j+1]=='-' ) { store2[j]=store[k]; store2[++j]='0'; k++; } } store2[i+1]='\0'; cout<<endl; const int number=i+1; for( int h=0;h<=i;h++) { printf("%c",store2[h]); } int a=0; c=store2[a++]; while(c!='\0') { while(c>='0'&&c<='9'||isdigit(store[x-1])&&c=='.')// 如果是数字就把它存在数组里 { store[x]=c; x++; //cout<<c<<" "; // cin>>c; c=store2[a++]; if((c<'0'||c>'9')&&c!='.')//如果是符号就输出空格 { store[x]=' ';//为什么不是直接存入数组里呢? 因为,如果直接存进去不就还是中缀表达式么- - ; x++; // cout<<" "; } if('#'==c)//如果是# 就跳出循环 goto f; } if(')'==c) { l.pop(&l,&e); while('('!=e) { store[x]=e; x++; store[x]=' '; x++; // cout<<e<<" "; l.pop(&l,&e); } } else if ('+'==c||'-'==c)//如果不是右括号,那么接下来只能 进行弹出(除非栈为空); { if(!l.stacklength()) { l.push(&l,c); } else//如果不是空栈的话,就要全部出栈。 { do { l.pop(&l,&e); if('('==e) { l.push(&l,e);//如果遇到左括号的话,就不能把左括号弹出来(因为前面还没有遇到右括号); } else { store[x]=e; x++; store[x]=' '; x++; //cout<<e<<" "; } }while(l.stacklength()&&'('!=e); //把栈里面的所有的符号 出栈后 再把前面的那个 输入的元素 + 或者 -入栈 l.push(&l,c); } } else if ('*'==c||'/'==c||'('==c)//乘除 和左括号 毫不犹豫的入栈//优先级最高 { l.push(&l,c); } c=store2[a++]; //cin>>c;// 这个输入对应前面 while (c !='#') ,因为每次输入都要判断下; } //f 为跳出循环的地方 f:while(l.stacklength())// 输出完数字后,栈中可能还存有 一些符号,要把那些符号都 输出来 { l.pop(&l,&e);//例如 1+(2-3)*4+10/5 结果为 1 2 3 - 4 * + 10 5 / + //因为前面的压栈是见到 乘除直接压栈的,只有遇到 了+- 才能把乘除 出栈 例如把这段while 循环的代码注释掉, 即 //f: 之后 就return ,那么 1 2 3 - 4 * + 10 5 / + 中的 "/ +" 就不会数出来,因为,前面我们已经说的很清楚了 //同级别的时候,才会把栈所有的元素数出来,因此,只有遇到 加号的时候 "/ +" 才会被输出,然后那个 同级别的+ 或者- //才会入栈 store[x]=e; x++; store[x]=' '; x++; //cout<<e<<" "; } store[x]='\0'; cout<<"以上的后缀表达式为:"<<endl; for( int h=0;h<=x;h++) { printf("%c",store[h]); } char str_num[12];// 把store 里面的数字都存起来. double f=0,g=0;//两个double 类型的运算数 seqstack_d d; d.inistack2(&d); int q = 0; /* char store2[150]; for(int i = 0; i <=x;i++) { if(store[i]!='(') { store2[i]=store[i]; } if (store[i]=='('&& store[i+1]=='-' ) { store2[i]=store[i]; store2[++i]='0'; } } cout<<endl; for( int h=0;h<=x;h++) { printf("%c",store2[h]); } */ for(int i =0;i<=x;i++) { while( isdigit(store[i]) ||store[i]=='.') { str_num[q++]=store[i++]; str_num[q]='\0'; if(q>=10)//数据不能太大 否则报错 { printf("出错了,输入数据过大\n"); return -1; } } q=0; if(store[i]==' '&&isdigit(store[i-1]))//空格前面必须是数字 才能让这个字符入栈,(因为空格前是符号的话,那前一个数字就入栈两次) {f=atof(str_num); d.push2(&d,f); } switch(store[i])//如果不是数字,我们就 直接运算 ,运算完丢回栈中 {case '+' : d.pop2(&d,&f); d.pop2(&d,&g); d.push2(&d,g+f); break; case '-' : d.pop2(&d,&f); d.pop2(&d,&g); d.push2(&d,g-f); break; case '*': d.pop2(&d,&f); d.pop2(&d,&g); d.push2(&d,g*f); break; case '/': d.pop2(&d,&f); d.pop2(&d,&g); if(f!=0) { d.push2(&d,g/f); } else { cout<<"输入出错"<<endl; return -1; } break; default :break; } } d.pop2(&d,&f) ; //将最后的结果出栈 ,赋值给f printf("\n以上的计算结果为: %.3f\n(结果保留3位小数)",f); return 0; }

    小数的解决是比较简单的,关键是负数的解决, - - 然后我想了一下,如果,把从控制台输入的(-a),改成 (0-a) 不就可以了嘛? 还真的是呢, 因此,我们得需要一个数组 来存储全部从控制台输入的字符,在store[]里面,然后 再对这个store []进行处理: 判断 是否碰到 ‘(’ 和 ‘(’ 的下一个字符是不是’-’ ,如果是,就修改这个字符串 , 把(-a)改成(0-a)。然后 存储在store2[]里面, 然后给 再去while 循环一个一个 的判断 把它弄成一个 后缀表达式,然后用栈的特性,把结果算出来! 运行结果如下:

    感谢每一个阅读的人!

    创作打卡挑战赛 赢取流量/现金/周边激励大奖
    转载请注明原文地址:https://blackberry.8miu.com/read-44669.html
    最新回复(0)