一、目标与要求
实现表达式的计算功能。其中,表达式操作数为个位数,操作符包括加减乘除与括号。
二、工具/准备工作
编程使用VC6.0完成
三、实验分析
1、首先需构建一个栈类,这里选择顺序栈
2、其次需构建将中缀表达式转换为后缀表达式的函数,过程中还需构建操作符优先值函数
3、最后构建计算后缀的函数
计算后缀中需要将char型的操作数转换为float型
四、实验步骤
- 完成栈类的构建
成员数据包括
int count; //元素个数
int maxsize; //最大个数
ElemType *elems; //存储元素
栈成员函数包括
Stack(int size=DEFAULT_SIZE); //构造函数
virtual ~Stack(); //析构函数
int Length() const; //返回栈元素个数
bool Empty() const; //判断栈是否为空
void Clear(); //清空栈
bool Push(const ElemType &e); //插入元素e为新的栈顶元素
bool Top(ElemType &e)const; //用e返回栈顶元素
bool Pop(ElemType &e); //删除栈顶元素,并用e返回栈顶元素
- 编写中缀变后缀的函数及相关操作符优先值函数,中缀变后缀大致思路如下:
先开一块char型数组p准备用于存放后缀表达式。
然后开启循环,逐个读取输入的中缀表达式的字符,如果读取的字符是操作数或“(”,直接进入p;如果是“+”“-”“*”“/”,栈空则直接进栈,栈非空则取栈顶元素,若栈顶元素的优先值小于读取字符的优先值,则将该字符进栈,如果栈顶元素的优先值大于等于读取字符的优先值,栈顶元素出栈并加入数组p,并取新的栈顶元素重复上述操作;如果读取的字符是“)”,则依次取栈顶元素出栈、加入p,直到遇到“(”为止,左右括号不加入p 。继续读取下一字符,直到遇到“=”为止。
循环结束后,将栈内元素从栈顶依次取出,加入到p,完成表达式中缀变后缀,p即为所求的后缀表达式。
- 编写计算后缀的函数,大致思路如下:
读取所求的后缀表达式,遇到操作数转化为float型直接进栈,遇到操作符则从栈顶取两个元素,进行该操作符相应的计算,将计算结果入栈后继续读取下一字符。循环结束后栈里的元素即为表达式的值。
4.编写main函数,调试、完善程序。
五、测试与结论
输入表达式,运行结果与实际值一致
当表达式中有除数为0时,程序予以提示
六、实验总结
算法能够实现表达式的计算,顺利完成了目标。表达式除了可以进行“+”“-”“*”“/”运算外,还可进行括号的运算。
独立编写了栈类、中缀转后缀、计算后缀三大部分,思路清晰。
感悟
- 数据结构的编程题,无论是代码复杂程度还是代码量,都比大一时的C++有较大提升,编程能力还需提高。
- 编程需要更加注重规范性,大一时编程常常忽略const等细节的使用,现在需要规范起来。
- 无论是在编写程序时还是调试程序时,都要注意中英文,尤其在调试程序输入时要切成英文。
具体代码如下:
include<iostream.h>
#include<math.h>
#include<string.h>
#define DEFAULT_SIZE 20
template<class ElemType>
class Stack
{protected:
int count;
int maxsize;
ElemType *elems;
public:
Stack(int size=DEFAULT_SIZE); //构造函数
virtual ~Stack(); //析构函数
int Length() const; //返回栈元素个数
bool Empty() const; //判断栈是否为空
void Clear(); //清空栈
bool Push(const ElemType &e); //插入元素e为新的栈顶元素
bool Top(ElemType &e)const; //用e返回栈顶元素
bool Pop(ElemType &e); //删除栈顶元素,并用e返回栈顶元素
};
template<class ElemType>
Stack<ElemType>::Stack(int size)
{maxsize=size;
elems=new ElemType[maxsize];
count=0;
}
template<class ElemType>
Stack<ElemType>::~Stack()
{delete []elems;
}
template<class ElemType>
int Stack<ElemType>:: Length() const
{return count;
}
template<class ElemType>
bool Stack<ElemType>:: Empty() const
{return count==0;
}
template<class ElemType>
void Stack<ElemType>::Clear()
{count=0;
}
template<class ElemType>
bool Stack<ElemType>::Push(const ElemType &e)
{if(count==maxsize)
{return 0;
}
else
{elems[count++]=e;
return 1;
}
}
template<class ElemType>
bool Stack<ElemType>::Top(ElemType &e) const
{if(Empty())
{return 0;
}
else
{e=elems[count-1];
return 1;
}
}
template<class ElemType>
bool Stack<ElemType>::Pop(ElemType &e)
{if(Empty())
{return 0;
}
else
{e=elems[count-1];
count--;
return 1;
}
}
int y(char a) //操作符优先值
{if(a=='-'||a=='+') return 1;
else if(a=='*'||a=='/') return 2;
else if(a=='(') return 0;
else {cout<<"请检查表达式是否正确"<<endl;return -1;}
}
void Transform(char *e) //将中缀转为后缀
{char p[DEFAULT_SIZE],t;
Stack<char> str;
int j=0;
for(int i=0;i<strlen(e)-1;i++)
{if(48<=e[i]&&e[i]<=57)
{p[j++]=e[i];
}
else if(e[i]==')')
{while(1)
{str.Pop(t);
if(t!='(')
p[j++]=t;
else
break;
}
}
else if(e[i]=='(')
{str.Push(e[i]);}
else
{
while(str.Empty()==0)
{str.Top(t);
if(y(t)>=y(e[i]))
{str.Pop(t);
p[j++]=t;
}
else break;
}
str.Push(e[i]);
}
}
while(str.Empty()==0)
{str.Pop(t);
p[j++]=t;
}
p[j++]='=';
p[j]='\0';
strcpy(e,p);
}
float Calculator(char *e) //计算后缀
{int i=0;
float z;
float t,t1,t2;
Stack<float> str;
while (e[i]!='=')
{if(48<=e[i]&&e[i]<=57)
{t=e[i]-48; //将字符数字转为浮点数
str.Push(t);
}
else if(e[i]=='+')
{str.Pop(t2);
str.Pop(t1);
t=t1+t2;
str.Push(t);
}
else if(e[i]=='-')
{str.Pop(t2);
str.Pop(t1);
t=t1-t2;
str.Push(t);
}
else if(e[i]=='*')
{str.Pop(t2);
str.Pop(t1);
t=t1*t2;
str.Push(t);
}
else if(e[i]=='/')
{ str.Pop(t2);
str.Pop(t1);
if(fabs(t2)>0.00001)
{t=t1/t2;
str.Push(t);
}
else
{cout<<"除数为0,无法计算"<<endl;break;}
}
else{cout<<"请检查表达式是否正确"<<endl;break;
}
i++;
}
str.Top(z);
return z;
}
void main()
{
char p[DEFAULT_SIZE];
cout<<"请输入表达式,以 = 结尾,注意输入法调为英文"<<endl;
cin.getline(p,DEFAULT_SIZE);
Transform(p);
cout<<Calculator(p)<<endl;
}