通过栈来实现简单的四则运算,数字0~9,不考虑负数,但是可以带括号。用的c++。结果是double精度。
一、前中后缀表达式。
先解释一下算术表达式的前中后缀表达式,例如下面的一个简单的二叉树:
每一个二叉树都有他自己的左子树和右子树,以及根。
前缀表达式的顺序就是:根左右。就上面的二叉树而言就是:+A/*B-C+DFE。
中缀表达式的顺序就是:左根右。即我们正常的顺顺序:A+B*C-D+F/E
后缀表达式的顺序就是:左右根。即ABCDF±*E/+
二、中缀表达式转后缀表达式
定义栈类,通过符号栈先将中缀表达式转为后缀表达式,通过后缀表达式进行计算。
首先,中缀表达式转后缀表达式:定义符号栈对象ope。
遍历表达式str。
如果遇到的是数字,就将数字写入后缀表达式的存储字符串str2中。
否则,如果ope是空的或者str[i]是‘(’即左括号,直接将运算符str[i]写入ope栈。
否则,用temp记录符号栈的栈顶元素,去判断栈顶元素和str[i]的优先级。
如果栈顶元素是‘*’*或者*‘/’。
如果str[i]是‘*’或者‘/’,即优先级相同,遵循从左到右计算的原则,将栈顶元素弹出,写入str2,str[i]入栈。
如果str[i]是‘+’或者‘-’,即优先级低于栈顶元素,则将栈中:有左括号‘(’就把‘(’之前的元素全部出栈,写入str2,没有左括号‘(’就全部出栈,写入str2,str[i]入栈。
如果str[i]是右括号,就将栈内遇到的第一个‘(’前的所有元素都出栈,写入str2,左括号也弹出栈。
如果栈顶元素是‘+’或者‘-’。
如果str[i]是‘*’或‘/’,优先级高于栈顶元素,直接入栈,即str[i]入栈。
如果str[i]是‘+’或者‘-’,优先级相同,遵循从左到右的计算原则,将栈顶元素出栈,写入str2,str[i]进栈。
如果str[i]是右括号‘)’,就将栈内遇到的第一个‘(’前的所有元素都出栈,写入str2,左括号也弹出栈。
如果栈顶元素是‘(’,str[i]直接进栈。
如果栈内还有符号,全部出栈,写入str2。
这样得到的str2就是后缀表达式。
三、后缀表达式计算
定义数字栈number。定义计算结果的变量num。
遍历str2:
如果str2[i]大于等于‘0’小于等于‘9’,就将str2[i]-48转成数字写入数字栈number。
否则,str2[i]是符号,就从数字栈中出弹出两个数字,第一个弹出的数字为num2,第二个弹出额数字是num1。
如果str2[i]是‘+’,则num=num2+num1。
如果str2[i]是‘-’,则num=num2-num1。
如果str2[i]是‘*’, 则num=num2*num1。
如果str2[i]是‘/’, 则num=num2/num1。
将计算后的num入栈。
最终,数字栈只有一个元素,即为计算所得的结果。
具体代码
#include <iostream>
#include<string>
#include<iomanip>
using namespace std;
template<class T>
class Arraystack//栈
{
private:
T *stack;
int arraylength;
int stackTop;
public:
Arraystack(int n)
{
arraylength = n;
stack = new T[arraylength];
stackTop = -1;
}
Arraystack(const Arraystack&rv)
{
arraylength = rv.arraylength;
stackTop = rv.stackTop;
stack = new T[arraylength];
for (int i = 0; i <= stackTop; i++)
{
stack[i] = rv.stack[i];
}
}
~Arraystack()
{
delete[]stack;
}
public:
bool empty()
{
//int size = size();
if (size() == 0)
{
return true;
}
return false;
}
int size() { return stackTop + 1; };
T& top()//得到栈顶元素
{
if (stackTop != -1)
{
return stack[stackTop];
}
else
{
cout << "strack is empty!" << endl;
exit(-1);
}
}
void pop()//删除栈顶元素
{
if (stackTop != -1)
{
//stack[stackTop].~T();
stackTop--;
//cout << "stackTop" << stackTop << " ";
}
}
void push(const T& element)//向栈内添加元素
{
if (stackTop == arraylength - 1)//如果空间已满
{
T* temp = new T[arraylength];
for (int i = 0; i <= stackTop; i++)
{
temp[i] = stack[i];
}
delete[]stack;
stack = new T[arraylength * 2];
arraylength = arraylength * 2;
for (int i = 0; i <= stackTop; i++)
{
stack[i] = temp[i];
}
}
stackTop++;
stack[stackTop] = element;
}
};
string change(string &str)//中缀表达式变成后缀表达式
{
Arraystack<char>ope(50);//符号栈
string str2;//存储后缀表达式
str2.clear();
for (int i = 0; i < (int)str.size(); i++)
{
if (str[i] >= '0'&&str[i] <= '9')//如果是数字
{
str2.push_back(str[i]);
}
else//如果是运算符
{
if (ope.empty() || str[i] == '(')//如果符号栈为空或者是左括号,直接压入栈
{
ope.push(str[i]);
}
else//判断优先级
{
char temp = ope.top();
if (temp == '*' || temp == '/')//如果符号栈栈顶元素为乘或除
{
if (str[i] == '*' || str[i] == '/')//如果符号优先级与栈顶元素相同,遵守从左到右原则,栈顶元素出栈,符号进栈
{
ope.pop();
str2.push_back(temp);
ope.push(str[i]);
}
else if (str[i] == '+' || str[i] == '-')//如果优先级低,则栈内'('前所有元素出栈,符号进栈
{
int size = ope.size();
for (int j = size - 1; j >= 0; j--)
{
char top = ope.top();
ope.pop();
if (top == '(')
{
ope.push(top);
break;
}
else
{
str2.push_back(top);
}
}
ope.push(str[i]);
}
else if (str[i] == ')')//如果符号是右括号,则栈内'('前所有元素都出栈
{
for (int j = ope.size() - 1; j >= 0; j--)
{
char top = ope.top();
ope.pop();
if (top == '(')
{
break;
}
else
{
str2.push_back(top);
}
}
}
}
else if (temp == '+' || temp == '-')//如果栈顶元素是加或者减
{
if (str[i] == '*' || str[i] == '/')//如果符号优先级高,符号进栈
{
ope.push(str[i]);
}
else if (str[i] == '+' || str[i] == '-')//如果优先级相同,则栈顶元素出栈,符号进栈
{
ope.pop();
str2.push_back(temp);
ope.push(str[i]);
}
else if (str[i] == ')')//如果符号是右括号,则栈内'('前所有元素都出栈
{
for (int j = ope.size() - 1; j >= 0; j--)
{
char top = ope.top();
ope.pop();
if (top == '(')
{
break;
}
else
{
str2.push_back(top);
}
}
}
}
else if (temp == '(')//如果栈顶元素是左括号,直接进栈
{
ope.push(str[i]);
}
}
}
}
if (ope.size() != 0)//如果符号栈内仍有元素,出栈
{
int size = ope.size();
for (int i=size-1;i>=0;i--)
{
char top = ope.top();
ope.pop();
str2.push_back(top);
}
}
return str2;
}
double calculate(string str)//利用后缀表达式计算结果
{
Arraystack<double>number(50);
for (int i = 0; i < (int)str.size(); i++)
{
if (str[i] >= '0'&&str[i] <= '9')
{
double s = (double)(str[i] - 48);
number.push(s);
}
else
{
double num2 = number.top();
number.pop();
double num1 = number.top();
number.pop();
double sum = 0;
if (str[i] == '+')
{
sum = num1 + num2;
}
else if (str[i] == '-')
{
sum = num1 - num2;
}
else if (str[i] == '*')
{
sum = num1 * num2;
}
else if (str[i] == '/')
{
sum = num1 / num2;
}
number.push(sum);
}
}
return number.top();
}