8.⽤CC++实现⼀个科学计算器———(超级详细完整,包含
CC++版本和Qt 版本)
⽬录
1.需求分析
编程实现⼀个科学计算器(类似于Windows⾃带的计算器),要求能够实现加减乘除混合运算,并且能够识别括号,优先级正确。下⾯是本博客的Qt版本的计算器效果图
2.主要难点——逆波兰算法
2.1 中缀表达式转换为后缀表达式
我们⽇常所⽤的数学表达式(如5+3)都是中缀表达式,中缀表达式是⼈容易理解的表达式。后缀表达式⼜叫做逆波兰表达式,对计算机来说,计算中缀表达式是很困难的,但是计算后缀表达式却⾮常容易,所以我们先把中缀表达式转化成后缀表达式来计算。下⾯的动态图和算法流程图可以很好的演⽰整个转换的过程:
图1  中缀表达式转后缀表达式的动态图
图2  中缀表达式转后缀表达式的流程图
2.2 后缀表达式的计算
后缀表达式的计算是⽐较简单的,基本思路就是遇到操作符就将操作数出栈并根据操作符进⾏计算,并将结果进栈,如果没有遇到操作符,就直接将操作数进栈。下图是具体的流程图,注意下⾯的代码使⽤'\0'作为表达式的终⽌符号(本⼈偷懒使⽤了别⼈的流程图)
图3  后缀表达式的计算---动态图
图4  后缀表达式的计算----流程图
3.编程实现
3.1  C/C++版本
在编程的时候,刚开始准备使⽤C语⾔,编程的过程中发现,在中缀转后缀表达式的时候需要⼀个存
放字符型元素的栈,⽽后缀表达式的计算中⼜需要⼀个存放double型元素的栈,这样⼀来,就需要分别编写两个栈,很⿇烦。下⾯的代码是直接⽤C++的类模板来实现的,程序⽐C语⾔简单很多,当然纯粹⽤C语⾔肯定也是没有任何问题的。
实际编程中还需要考虑正负号,因为‘+’和‘-’有时候不表⽰加减,为了解决这个问题,可以将负数-a看成是0-a,把正数+a看成0+a,这样⼀来,正负号的问题也解决了。
(1)类的声明    calculator.h
#ifndef CALCULATOR_H
#define CALCULATOR_H
enum MAXSIZE
{
STACK_INIT_SIZE=20,//定义初始最⼤容量
STACKINCREMENT=10,//栈满的时候,动态增加容量,每次增加10个元素空间    MAXBUFFER=10,//最⼤缓冲区
MAX_EXP_LEN=100//表达式最长为100
};
template<typename ElemType>
class Calculator
{
public:
struct sqStack
{
ElemType *base;//指向栈顶
ElemType *top;
int stackSize;//当前栈的最⼤容量
};
Calculator();
~Calculator();
void Push(ElemType e);
bool Pop(ElemType &e);
void clearStack();
int StackLen();
int Calculation(char Postfix[]);//后缀表达式的计算
bool Infix2Postfix(char Infix[],char Postfix[]);//中缀表达式变为后缀表达式
private:
sqStack s;
};
#endif // CALCULATOR_H
(2)类的实现  calculator.cpp
#include "calculator.h"
#include <stdio.h>
template<typename ElemType>
Calculator<ElemType>::Calculator()
{
s.base=new ElemType[STACK_INIT_SIZE];//栈底指向申请空间的⾸地址
if(s.base==NULL)//申请失败
exit(0);
s.stackSize=STACK_INIT_SIZE;
}
//销毁栈,将内存空间释放
科学计算器使用template<typename ElemType>
Calculator<ElemType>::~Calculator()
{
delete []s.base;
}
template<typename ElemType>
void Calculator<ElemType>::Push(ElemType e)
{
{
p-s.base>=s.stackSize)
{
s.base=(ElemType *)realloc(s.base,(s.stackSize+STACKINCREMENT)*sizeof(ElemType));        //        realloc是申请⼀个新的空间,并将旧的内容拷贝到新的空间,还会释放以前的空间
if(s.base==NULL)
exit(0);
s.stackSize=s.stackSize+STACKINCREMENT;//当前栈的最⼤容量变⼤了
}
*(s.top)=e;
}
template<typename ElemType>
bool Calculator<ElemType>::Pop(ElemType &e)
{
p==s.base)
return false;//空栈
e=*(--(s.top));
return true;
}
//清空栈,不改变物理空间
template<typename ElemType>
void Calculator<ElemType>::clearStack()
{
}
//计算栈的当前容量(存储的数据量或者元素个数)
template<typename ElemType>
int Calculator<ElemType>::StackLen()
{
p-s.base;
}
template<typename ElemType>
int Calculator<ElemType>::Calculation(char Postfix[])
{
int i=0,j;
char c;
char str[MAXBUFFER];
double a=0,b=0;
for(j=0;Postfix[j]!='\0';j++)
{
//        c=Postfix[j];
while ((Postfix[j]>=48)&&(Postfix[j]<=57)||Postfix[j]=='.') //输⼊的是数字
{
str[i]=Postfix[j];
//            printf("str[%d]=%c\n",i,c);
i++;
str[i]='\0';
if(i>=10)
{
printf("出错,输⼊的数据长度过⼤!\n");
return -1;
}
//            scanf("%c",&c);
j++;
if((Postfix[j]==' '))
{
//                str[i]='\0';
//                printf("str[%d]=%c\n",i,Postfix[j]);
a=atof(str);
//                printf("%f \n",a);
Push(a);
i=0;
}
}
switch (Postfix[j])
{
case '+':
Pop(a);
if(!Pop(b))//防⽌这是符号位(单⽬运算符)
{
Push(a);
break;
}
Pop(b);
//            printf("%f+%f=%f\n",b,a,b+a);
Push(b+a);
break;
case '-':
Pop(a);
if(!Pop(b))//
{
Push(-a);
break;
}
//            printf("%f-%f=%f\n",b,a,b-a);
Push(b-a);
break;
case '*':
Pop(a);
Pop(b);
//            printf("%f*%f=%f\n",b,a,b*a);
Push(b*a);
break;
case '/':
Pop(a);
if(a==0)
{
printf("除数不能为零!\n");
return -1;
}
Pop(b);
Push(b/a);
break;
default:
break;
}
}
Pop(a);
return a;
}
template<typename ElemType>
bool Calculator<ElemType>::Infix2Postfix(char Infix[],char Postfix[]) {
Calculator<char> s;
int i=0,j=0;
char e;
printf("中缀表达式为:");