实验3 算术表达式求值
一、实验目的:
熟练掌握栈的结构,以及这种数据结构的特点;
2. 能够在两种存储结构上实现栈的基本运算,特别注意栈满和栈空的判断条件及描述方法;
二、实验原理
要求输入表达式,判断括号是否匹配,若匹配则由中缀表达式转化为后缀表达式,并通过运算得出计算结果。
1. Match()验证括号是否匹配:当遇到左括号时就入栈,遇到右括号时就取栈顶元素,如果栈顶元素是左括号,那么匹配成功,同时将左括号出栈。不匹配情况:(1)左括号多,循环结束时,栈中还存在元素即左括号。(2)右括号多,取栈顶元素时,栈顶为空则没有左括号了。
2. 中缀转后缀:两个存储空间,str2存放数字或运算符,栈s存放运算符
(1)2+3*4:“*”号优先级大于“+”号,可直接入栈
首先2为数字插入str2尾部,“+”此时栈为空所以加号入栈,3为数字插入str2尾部,“*”号优先级大于“+”号,所以可以直接入栈,4为数字插入str2尾部,循环结束。但是此时栈不为空:把栈中所有元素出栈并插入str2尾部。得到:str2=“234*+”
(2)(2+3)*4:遇到右括号则栈中所有元素出栈,插入str2尾部
首先是“(”则可直接入栈,2为数字插入str2尾部,“+”号优先级大于“(”直接入栈,3为数字插入str2尾部,“)”则把栈中所有元素出栈,插入到str2尾部(左括号不插入),“*”此时栈为空可直接入栈,4为数字插入str2尾部,循环结束。但是此时栈中还有一个“*”号,把栈中所有元素出栈并插入str2尾部。得到:str2=“23+4*”
(3)2+3*4-5:减号优先级小于乘号,把栈中所有元素出栈,插入str2尾部
首先2为数字插入str2尾部,“+”此时栈为空可直接入栈,3为数字插入str2尾部,“*”号优先级大于“+”号可直接入栈,4位数字插入str2尾部,“-”号优先级低于“*”号,把栈中所有元素出栈,插入str2尾部,此时栈为空减号直接入栈,5为数字插入str2尾部,循环结束。但是此时栈中还有一个“-”号,把栈中所有元素出栈并插入str2尾部。得到:str2=“234*+5-”
3.通过后缀表达式计算结果:遇到数字就入栈ss中,遇到运算符就取栈顶的两个元素,进行计算,计算结果还放入栈ss中。最终计算结果在栈ss中。
三、参考程序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<malloc.h>
#include<string>
#include<stack>
using namespace std;
const int MaxSize=100;
stack<char> s; //定义一个栈s
stack<int> ss; //定义一个栈ss
typedef struct linknode
{
char data[MaxSize];
int top;
}SqStack;
//初始化栈
void initStack(SqStack *&s)
{
s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;
}
//入栈操作
bool Push(SqStack *&s,char e)
{
if(s->top==MaxSize-1) //栈已满
return false;
s->top++; //入栈
s->data[s->top]=e;
return true;
}
//出栈操作
bool Pop(SqStack *&s,char &e)
{
if(s->top==-1)
return false;
e=s->data[s->top];
s->top--;
return true;
}
//获得栈顶元素
bool GetTop(SqStack *s,char &e) {
if(s->top==-1) //栈已空
return false;
e=s->data[s->top];
return true;
}
//清空栈
bool StackEmpty(SqStack *s)
{
return(s->top==-1);
}
//销毁栈
void DestroyStack(SqStack *&s)
{
free(s);
}
//括号是否匹配
bool Match(char exp[],int n)
{
int i=0;
char e;
bool match=true;
SqStack *sq;
initStack(sq);
while(i<n && match)
{
if(exp[i]=='(') //如果当前元素为(
Push(sq,exp[i]); //将当前元素入栈
else if(exp[i]==')') //如果当前元素为)
{
if(GetTop(sq,e)==true) //存在栈顶元素
{
if(e!='(') //如果该元素不是左括号
match=false; //则不匹配
else
Pop(sq,e); //是左括号就出栈
match = true;
}
else match=false; //若栈为空,则不匹配
}
if(exp[i]=='[') //如果当前元素为【
Push(sq,exp[i]); //将当前元素入栈
else if(exp[i]==']') //如果当前元素为】
{
if(GetTop(sq,e)==true) //取栈顶元素
{
if(e!='[') //如果该元素不是【
match=false; //则不匹配
else
Pop(sq,e); //否则,将该元素出栈
}
else match=false; //若栈为空,则不匹配
}
if(exp[i]=='{') //如果当前元素为 {
Push(sq,exp[i]); //将当前元素入栈
else if(exp[i]=='}') //如果当前元素为 }
{
if(GetTop(sq,e)==true) //取栈顶元素
{
if(e!='{') //如果该元素不是 {
match=false; //则不匹配
else
Pop(sq,e); //否则,将该元素出栈
}
else match=false; //若栈为空,则不匹配
}
++i; //判断下一个元素
}
if(!StackEmpty(sq)) match=false; //执行完上述程序后,如果栈不为空 ,则匹配不成功,因为只要匹配就把左括号出栈了,如果还有表示多左括号
DestroyStack(sq); //销毁栈
return match; //返回match值
}
int main()
{
char st[100];
int len1, len2, len, i, j;
string str1, str2;//str1为中缀表达式,str2为后缀表达式
//检测Match()函数值
cout<<"请输入表达式:"<<endl;
cin>>st; //输入字符
int len0=strlen(st);//所输入字符串的实际长度
bool m=Match(st,len0);//通过match()函数判断输入的式子中括号是否匹配
//中缀表达式转换为后缀表达式
if (m==true)
{ //如果match=true
cout<<"ok!"<<endl; //输出匹配成功
cout<<"请再次输入刚刚输入过的表达式:"<<endl;
cin>>str1;
len1 = str1.length(); //中缀表达式的长度
str2.clear(); //清除流的错误状态
//原则:数字存入字符串str2尾部,运算符进栈或出栈
for (i = 0; i < len1; i++){
if (str1[i] >= '0' && str1[i] <= '9')
str2.push_back(str1[i]); //如果是中缀表达式中的数字,则在后缀表达式字符串尾部插入这个数字
else{
if (s.size() == 0 || str1[i] == '(') //如果栈s中元素数目为0,或者该元素是中缀表达式中的(
s.push(str1[i]); //让该元素进栈
else{
char tmp1 = s.top(); //将栈顶元素赋给tmp1
if (str1[i] == ')')//如果该元素是右括号,就把栈中所有元素出栈,并插入str2尾部
{
len = s.size(); //将s栈中元素数目赋给len
while (len)
{ //len不为空
char tmp = s.top();//将栈s的栈顶元素赋给tmp变量
s.pop(); //出栈
if (tmp == '(') //如果tmp等于左括号, 不加入str2中
break; //跳出while循环
else
str2.push_back(tmp); //否则将tmp插入到后缀表达式字符串尾部
len--; //长度-1
}
}
else{
if (tmp1 == '*' || tmp1 == '/'){ //如果栈顶元素tmp1为*号或/号
if (str1[i] == '*' || str1[i] == '/') //当前元素也为*号或/号,优先级相同直接入栈
s.push(str1[i]); //将该元素入栈
else{ //如果中缀字符串里的该元素不是*号或/号,优先级低,那么所有元素出栈,插到str2尾部
len = s.size();
while (len){
char tmp = s.top();
str2.push_back(tmp);
s.pop();
len--;
}
s.push(str1[i]);
}
}
else{ //如果栈顶元素tmp1不为*号或/号
s.push(str1[i]); //将该元素入栈
}
}
}
}
}
if (s.size() != 0){ //循环结束后如果栈中还有元素,则全部出栈,插到str2尾部
len = s.size();
while (len){
char tmp = s.top();
str2.push_back(tmp); //并添加到后缀表达式后边
s.pop(); //将所有元素出栈
len--;
}
}
cout << "后缀表达式为:"<<endl<<str2 << endl;
//由后缀表达式计算结果
//str2是字符串,ss为栈
int temp1, temp2, temp3;
len2 = str2.length(); //后缀表达式长度
for (i = 0; i < len2; i++){
if (str2[i] >= '0' && str2[i] <= '9'){ //当前字符串是数字就入栈
int t = str2[i]-48;
ss.push(t);
}
else{ //如果新存入的不是数字,而是运算符,就把栈中最上面的两个元素出栈,通过计算再入栈
temp1 = ss.top();
ss.pop();
temp2 = ss.top();
ss.pop();
if (str2[i] == '+'){
temp3 = temp2 + temp1;
}
else if (str2[i] == '-'){
temp3 = temp2 - temp1;
}
else if (str2[i] == '*'){
temp3 = temp2 * temp1;
}
else if (str2[i] == '/'){
temp3 = temp2 / temp1;
}
ss.push(temp3);//得到计算结果后,还入栈
}
}
cout <<"计算结果为:"<<endl<< ss.top() << endl;
}
else {
cout<<"error!"<<endl; //否则,输出匹配为假
}
return 0;
}
/*运算结果:
请输入表达式:
4+(9-3)
ok!
请再次输入刚刚输入过的表达式:
4+(9-3)
后缀表达式为:
493-+
计算结果为:
10
*/