栈ADT应用:中缀表达式求值
栈ADT应用:中缀表达式求值
表达式求值是进行数据处理的最基本操作。请编写程序完成一个简单算术表达式的求值。要求如下:
(1) 运算符包括:+、-、*、-、^(乘方)、括号
(2)运算量为数值常量,根据自己的能力可以对运算量做不同的约束,例如1位整数、多位整数、实数等(会有不同的测试用例);
输入:一行,即表达式,以“=”结束。例如:
5*(8-3)+6/5=
输出:一行,即表达式的值。结果值为整数时输出为整数,如果有小数时保留5位小数。
26.20000
测试用例
输入 | Result |
---|---|
5+(3-1)/2= | 6 |
总结:
因为老师让练习写栈的ADT,所以就没用stl的栈。
另外,<stdlib.h>中的 double atof(char &x)可以将字符串转化为数字,直至遇到第一个不为数字的字符
#include <iostream>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
class SeqStack1 //运算符栈
{
//顺序栈类定义
public:
char *elements; //数组存放栈元素
int top=-1; //栈顶指示器
int maxSize; //栈最大容量
void overflowProcess(); //栈的溢出处理
SeqStack1() {}
SeqStack1(int sz); //构造函数
~SeqStack1()
{
delete []elements;
}
void Push(char x); //进栈
bool Pop(char x); //出栈
bool GetTop(char &x); //取栈顶内容
bool IsEmpty()const
{
return top==-1;
}
bool IsFull()const
{
return top==maxSize-1;
}
int GetSize()const
{
return top+1;
}
void MakeEmpty()
{
top=-1;
}
//friend ostream&operator<<(ostream &os,SeqStack &S); //重载运算符<<
};
bool SeqStack1::GetTop(char &x)
{
if(top==-1)
{
return false;
}
else
{
x=elements[top];
return true;
}
}
SeqStack1::SeqStack1(int sz) //构造函数
{
elements=new char[sz]; //申请连续空间
assert(elements!=NULL); //头文件,#include <assert.h>,宏断言,如果括号内语句是假就结束程序
top=-1; //栈顶指示器指向栈底
maxSize=sz; //栈的最大空间
}
void SeqStack1::overflowProcess()
{
//私有函数,当栈满则执行扩充栈存储空间处理
char *newArray=new char[2*maxSize]; //创建更大的存储数组
for(int i=0; i<=top; i++)
{
newArray[i]=elements[i];
}
maxSize+=maxSize; //栈空间扩大
delete []elements; //释放原来的连续空间
elements=newArray; //改变elements指针
}
void SeqStack1::Push(char x)
{
//若栈满,则溢出处理,将元素X插入该栈栈顶
if(IsFull()==true)
overflowProcess(); //栈满
top++;
elements[top]=x; //栈顶指针先+1.再元素进栈
}
bool SeqStack1::Pop(char x)
{
//若栈不空,函数退出栈顶元素并将栈顶元素赋值给X
//返回true,否则返回false
if(IsEmpty()==true)
return false;
x=elements[top--]; //先去元素,栈顶指针退1
return true; //退栈成功
}
class SeqStack2
{
//顺序栈类定义
public:
double *elements; //数组存放栈元素
int top=-1; //栈顶指示器
int maxSize; //栈最大容量
void overflowProcess(); //栈的溢出处理
SeqStack2() {}
SeqStack2(int sz); //构造函数
~SeqStack2()
{
delete []elements;
}
void Push(double x); //进栈
bool Pop(double x); //出栈
bool GetTop(double &x); //取栈顶内容
bool IsEmpty()const
{
return top==-1;
}
bool IsFull()const
{
return top==maxSize-1;
}
int GetSize()const
{
return top+1;
}
void MakeEmpty()
{
top=-1;
}
//friend ostream&operator<<(ostream &os,SeqStack &S); //重载运算符<<
};
SeqStack2::SeqStack2(int sz) //构造函数
{
elements=new double[sz]; //申请连续空间
assert(elements!=NULL); //头文件,#include <assert.h>,宏断言,如果括号内语句是假就结束程序
top=-1; //栈顶指示器指向栈底
maxSize=sz; //栈的最大空间
}
void SeqStack2::overflowProcess()
{
//私有函数,当栈满则执行扩充栈存储空间处理
double *newArray=new double[2*maxSize]; //创建更大的存储数组
for(int i=0; i<=top; i++)
{
newArray[i]=elements[i];
}
maxSize+=maxSize; //栈空间扩大
delete []elements; //释放原来的连续空间
elements=newArray; //改变elements指针
}
void SeqStack2::Push(double x)
{
//若栈满,则溢出处理,将元素X插入该栈栈顶
if(IsFull()==true)
overflowProcess(); //栈满
top++;
elements[top]=x; //栈顶指针先+1.再元素进栈
}
bool SeqStack2::Pop(double x)
{
//若栈不空,函数退出栈顶元素并将栈顶元素赋值给X
//返回true,否则返回false
if(IsEmpty()==true)
return false;
x=elements[top--]; //先去元素,栈顶指针退1
return true; //退栈成功
}
int isp(char a) //优先数
{
if(a=='#')
{
return 0;
}
else if(a=='=')
{
return 0;
}
else if(a=='(')
{
return 0;
}
else if(a=='^')
{
return 5;
}
else if(a=='*'||a=='/')
{
return 4;
}
else if(a=='+' || a=='-')
{
return 3;
}
else if(a==')')
{
return 0;
}
}
void DoOperator(SeqStack1 &op,SeqStack2 &figer)
{
//取两个操作数,根据操作符op形成运算指令并计算
double left,right,value;
right=figer.elements[figer.top]; //最上边的操作符取出来,出栈
figer.Pop(right);
left=figer.elements[figer.top];
figer.Pop(left);
char opp=op.elements[op.top]; //令op=栈顶运算符
//取操作数成功,计算并进栈
if(opp=='+')
{
value=left+right; //计算结果
figer.Push(value); //结果压入栈中
}
else if(opp=='-')
{
value=left-right;
figer.Push(value);
}
else if(opp=='*')
{
value=left*right;
figer.Push(value);
}
else if(opp=='/')
{
if(right==0.0)
{
cerr<<"除数不能为零"<<endl;
}
else
{
value=left/right;
figer.Push(value);
}
}
else if(opp=='^')
{
value=pow(left,right);
figer.Push(value);
}
op.Pop(opp); //运算完的数字出栈
}
int main()
{
SeqStack1 op(100);
SeqStack2 figer(100);
string str;
cin>>str;
for(int i=0;i<str.length();i++)
{
if(isdigit(str[i])) //如果这个数是数字
{
double p=atof(&str[i]); //取整个数字
figer.Push(p); //把整个数字入栈了
while(isdigit(str[i]) || str[i]=='.')
{
i++; //把i移动到整个数字之后
}
i--;
}
else
{
if(str[i]=='(') op.Push('('); //括号单独处理
else if(str[i]==')')
{
while(op.elements[op.top]!='(')
DoOperator(op,figer);
op.Pop('(');
}
else if(op.IsEmpty() || isp(str[i])>isp(op.elements[op.top]))
//空栈或当前运算符比栈顶运算符优先,当前运算符进栈
{
op.Push(str[i]);
}
else if(op.IsEmpty()==false && op.top==0 && op.elements[op.top]=='=')
//栈不为空,且栈内只剩下一个‘=’时,出循环
{
break;
}
else if(op.IsEmpty()==false && isp(str[i])<=isp(op.elements[op.top]))
//栈不为空,且栈顶运算符优先于当前运算符时
{
while(op.IsEmpty()==false &&isp(str[i])<=isp(op.elements[op.top])) //栈顶运算符出栈运算直到当前运算符优先于栈顶运算符,当前运算符入栈
{
DoOperator(op,figer);
}
op.Push(str[i]);
}
}
}
// 这时候,运算符栈已经空了,数字栈还剩最后一个结果,
//判断这个结果是不是小数,选择不同的输出方式
if(ceil(figer.elements[0])!=floor(figer.elements[0]))
{
cout<<fixed<<setprecision(5)<<figer.elements[0];
}
else
cout<<figer.elements[0];
return 0;
}