Description
输入一个算术表达式,包括加、减、乘、除、四种运算,表达式中可以出现小括号,通过栈先将中缀表达式转换为后缀表达式,然后计算出表达式的结果
Input
输入一个算术表达式,注意以#结束
Output
输出表达式的结果,注意用cout 输出
Sample Input
2.4+2*(1.3+2.4)-4.8/4#
Sample Output
8.6
借助栈实现表达式的计算 思路
- 先建立模板栈,类型可以自己定义
- 将中序表达式转化为后序表达式函数,转化的后续表达式放到一个字符数组里
- 建立后序(逆波兰)表达式计算器函数,将字符组数传参到后序(逆波兰)表达式计算器函数
template<class T>
class stack
{
public:
stack(int max = 50);//默认构造maxsize默认值为max
~stack()
{
delete[] elements;
}
void push(const T& x);//入栈
void pop(T& x);//出栈
bool isEmpty();//判断栈是否为空
bool isFull();//判断栈是否为满
private:
int top;//当前的位置
int maxsize;
T* elements;
};
template<class T>
bool stack<T>::isEmpty()//判断栈是否为空
{
if (top == -1)
return true;
else return false;
}
template<class T>
bool stack<T>::isFull()//判断栈是否为满
{
return (top == maxsize - 1) ? true : false;
}
template<class T>
void stack<T>::push(const T& x)//入栈
{
if (isFull() == false)
{
elements[++top] = x;
}
}
template<class T>
void stack<T>::pop(T& x)//出栈
{
if (isEmpty() == false)
x = elements[top--];
}
template<class T>
stack<T>::stack(int max) :top(-1), maxsize(max)//默认构造maxsize默认值为max
{
elements = new T[max];
if (elements == NULL)
{
cerr << "error!" << endl;
exit(1);
}
}
1.将中序表达式转化为后序表达式函数
思路
1.输入一个中序表达式,以#结束。扫描它的每一个字符
2.如果扫描的是数字和点字符(比如’1’,‘1.0’,‘1.00’)的话直接用一个字符数组记录下它们,直到扫描到不是数字和点字符。用(atof())转化为double类型的值。用字符数组记录下来,记录一个空格。
3.如果扫描的是 + - / * ( ),分情况,看操作符优先级,判断是否入栈。
- 1.如果是右括号)的话直接不停的出栈。用字符数组记录下来,再记录一个空格。直釗最后左括号出栈匹配(括号不需要记录)。
- 2.如果是加和减±的话,需要不停出栈。看操作符优先级,先出栈判断,直到栈空或者出栈的是左括号,左括号要放回去(进栈),其他的话* / + - ,此处不能是),因为)早就出栈了。用字符数组记录下来,记录一个空格。最后再进栈
- 3.如果是*或者/或者左括号(则直接入栈
4.函数代码
void Middle_Order_To_Back_Order(char str[],int &i) {//中序转后序
stack<char> data1;
char ch;//控制台获得字符
char temp;//存放出栈临时的变量
cin >> ch;
while (ch!='#')
{
while (ch == '.' || ch >= '0' && ch <= '9')//要是数字直接输出
{
//cout << ch;
str[i++] = ch;
cin >> ch;
if (ch != '.' &&(ch < '0' || ch>'9')) {
// cout<< " ";
str[i++] = ' ';
}
}
if (ch == ')') {//要是右括号则出栈直到遇到右括号
data1.pop(temp);
while (temp != '(') {
//cout << temp<<" ";
str[i++] = temp;
str[i++] = ' ';
data1.pop(temp);
}
}
else if (ch == '+' || ch == '-') {//要是加减。 1.要是栈空,直接入栈。2.
if (data1.isEmpty() == true) {
data1.push(ch);
}
else {
do {
data1.pop(temp);
if (temp == '(') {
//遇到右括号,打扰了,回去吧
data1.push(temp);
}
else//其他的话* / + - ,此处不能是),因为)早就出栈了,所以直接出来吧
{
// cout << temp << " ";
str[i++] = temp;
str[i++] = ' ';
}
} while (data1.isEmpty() != true && temp != '(');//不能是空而且不能是左括号
data1.push(ch);
}
}
else if (ch == '*' || ch == '/' || ch == '(') {//要是 乘除左括号直接入栈
data1.push(ch);
}
else if (ch == '#') {
break;
}
else {
cout << "输入出错" << endl;
}
cin >> ch;
}
while (data1.isEmpty() != true) {
data1.pop(temp);
// cout << temp << " ";
str[i++] = temp;
str[i++] = ' ';
}
str[i] = '\0';
}
2. 建立后序(逆波兰)表达式计算器函数
思路,比如1.0 2.0 + # 输出 3.0
得到一个字符数组,扫描它的每一个字符
-
- 1.过滤数字。如果扫描的是数字和点字符(比如’1’,‘1.0’,‘1.00’)的话直接用一个字符数组记录下它们,直到扫描到是空格(作为一个数)。得到字符串后转化为double类型,然后入栈 ,现在入栈了 2.0 1.0
- 2.如果扫描的是±*/字符,先出栈两个数(栈空了),然后进行相应操作(注意栈的特点,例如减法先出来的数是减数,除数不能为0),然后得到结果,然后再进栈 3.0。
- 3.最后出栈的为计算结果 3.0
- 4.函数代码
void RPN(char arr[])//后序(逆波兰)表达式计算
{
stack<double> data2;//存放表达式的操作数
char ch;
char str[10];//操作数的最大范围为9位
double temp;//存放出栈临时的变量
double temp1;//存放出栈临时的变量
int i = 0;//计数单个浮点数的长度
int j = 0;//计数读取的字符串
//cin >> noskipws >> ch;
ch = arr[j++];
while (ch != '#') {
while (isOperands(ch)) {//过滤数字。得到字符后转化为double类型,然后入栈
str[i++] = ch;
if (i > 9) {
cout << "精度出错" << endl;
}
//cin >> noskipws >> ch;
ch = arr[j++];
if (ch == ' ') {
str[i] = '\0';
temp = atof(str);
data2.push(temp);
i = 0;//计数器回归0
break;
}
}
//cin >> noskipws >> ch;
ch = arr[j++];
switch (ch)
{
case '+': {
data2.pop(temp);
data2.pop(temp1);
data2.push(temp + temp1);
break;
}
case '-': {//注意先出来的数是减数
data2.pop(temp);
data2.pop(temp1);
data2.push(temp1 - temp);
break;
}
case '*': {
data2.pop(temp);
data2.pop(temp1);
data2.push(temp1 * temp);
break;
}
case '/': {
data2.pop(temp);
data2.pop(temp1);
if (temp == 0) {
cout << "除数为0" << endl;
exit(-1);
}
else data2.push(temp1 / temp);
break;
}
}
}
data2.pop(temp);
cout <<fixed << setprecision(1)<<temp<<endl;
}
3.主函数
int main()
{
char data[50] = { ' ' };
int i = 0;
Middle_Order_To_Back_Order(data, i);
data[i++] = '#';
data[i] = '\0';
i = 0;
RPN(data);
return 0;
}
4.全部代码
/*
*
*@author:一叶红尘雪
*
*/
#include"iostream"
#include"iomanip"
#include"string"
using namespace std;
template<class T>
class stack
{
public:
stack(int max = 50);//默认构造maxsize默认值为max
~stack()
{
delete[] elements;
}
void push(const T& x);//入栈
void pop(T& x);//出栈
bool isEmpty();//判断栈是否为空
bool isFull();//判断栈是否为满
private:
int top;//当前的位置
int maxsize;
T* elements;
};
template<class T>
bool stack<T>::isEmpty()//判断栈是否为空
{
if (top == -1)
return true;
else return false;
}
template<class T>
bool stack<T>::isFull()//判断栈是否为满
{
return (top == maxsize - 1) ? true : false;
}
template<class T>
void stack<T>::push(const T& x)//入栈
{
if (isFull() == false)
{
elements[++top] = x;
}
}
template<class T>
void stack<T>::pop(T& x)//出栈
{
if (isEmpty() == false)
x = elements[top--];
}
template<class T>
stack<T>::stack(int max) :top(-1), maxsize(max)//默认构造maxsize默认值为max
{
elements = new T[max];
if (elements == NULL)
{
cerr << "error!" << endl;
exit(1);
}
}
bool isOperands(char ch)//判断ch是否是' . '或者是字符数字
{
if (ch == '.' || (ch >= '0' && ch <= '9'))
{
return true;
}
else return false;
}
void RPN(char arr[])//后序(逆波兰)表达式计算
{
stack<double> data2;//存放表达式的操作数
char ch;
char str[10];//操作数的最大范围为9位
double temp;
double temp1;
int i = 0;
int j = 0;
//cin >> noskipws >> ch;
ch = arr[j++];
while (ch != '#') {
while (isOperands(ch)) {//过滤数字。得到字符后转化为double类型,然后入栈
str[i++] = ch;
if (i > 9) {
cout << "精度出错" << endl;
}
//cin >> noskipws >> ch;
ch = arr[j++];
if (ch == ' ') {
str[i] = '\0';
temp = atof(str);
data2.push(temp);
i = 0;//计数器回归0
break;
}
}
//cin >> noskipws >> ch;
ch = arr[j++];
switch (ch)
{
case '+': {
data2.pop(temp);
data2.pop(temp1);
data2.push(temp + temp1);
break;
}
case '-': {//注意先出来的数是减数
data2.pop(temp);
data2.pop(temp1);
data2.push(temp1 - temp);
break;
}
case '*': {
data2.pop(temp);
data2.pop(temp1);
data2.push(temp1 * temp);
break;
}
case '/': {
data2.pop(temp);
data2.pop(temp1);
if (temp == 0) {
cout << "除数为0" << endl;
exit(-1);
}
else data2.push(temp1 / temp);
break;
}
}
}
data2.pop(temp);
cout <<fixed << setprecision(1)<<temp<<endl;
}
void Middle_Order_To_Back_Order(char str[],int &i) {//中序转后序
stack<char> data1;
char ch;
char temp;
cin >> ch;
while (ch!='#')
{
while (ch == '.' || ch >= '0' && ch <= '9')//要是数字直接输出
{
//cout << ch;
str[i++] = ch;
cin >> ch;
if (ch != '.' &&(ch < '0' || ch>'9')) {
// cout<< " ";
str[i++] = ' ';
}
}
if (ch == ')') {//要是右括号则出栈直到遇到右括号
data1.pop(temp);
while (temp != '(') {
//cout << temp<<" ";
str[i++] = temp;
str[i++] = ' ';
data1.pop(temp);
}
}
else if (ch == '+' || ch == '-') {//要是加减。 1.要是栈空,直接入栈。2.
if (data1.isEmpty() == true) {
data1.push(ch);
}
else {
do {
data1.pop(temp);
if (temp == '(') {
//遇到右括号,打扰了,回去吧
data1.push(temp);
}
else//其他的话* / + - ,此处不能是),因为)早就出栈了,所以直接出来吧
{
// cout << temp << " ";
str[i++] = temp;
str[i++] = ' ';
}
} while (data1.isEmpty() != true && temp != '(');//不能是空而且不能是左括号
data1.push(ch);
}
}
else if (ch == '*' || ch == '/' || ch == '(') {//要是 乘除左括号直接入栈
data1.push(ch);
}
else if (ch == '#') {
break;
}
else {
cout << "输入出错" << endl;
}
cin >> ch;
}
while (data1.isEmpty() != true) {
data1.pop(temp);
// cout << temp << " ";
str[i++] = temp;
str[i++] = ' ';
}
str[i] = '\0';
}
int main()
{
char data[50] = { ' ' };
int i = 0;
Middle_Order_To_Back_Order(data, i);
data[i++] = '#';
data[i] = '\0';
i = 0;
RPN(data);
return 0;
}