在数据结构上遇到了这个题...但是觉得麻烦没写,想想还是要学的,特此记录下来。
以下是代码:
#include <Windows.h>
#include <iostream>
#include <vector>
#include <String>
#include <stack>
#include <cstdlib>
using namespace std;
/*
第一步,转换成后缀表达式
第二部,利用后缀表达式求解
如何转化为后缀表达式:
顺序扫描中序表达式
a) 是数字, 直接输出
b) 是运算符
i : “(” 直接入栈
ii : “)” 将符号栈中的元素依次出栈并输出, 直到 “(“, “(“只出栈, 不输出
iii: 其他符号, 将符号栈中的元素依次出栈并输出, 直到 遇到比当前符号优先级更低的符号或者”(“。 将当前符号入栈。
扫描完后, 将栈中剩余符号依次输出
*/
int main()
{
string str_in;
vector<string> houzhuibiaodashi; //后缀表达式
stack<char> CStack;
string temp; //临时
stack <float> NStack;
while (1)
{
houzhuibiaodashi.clear(); //后缀表达式向量清空
while (!CStack.empty()) //运算符栈清空
{
CStack.pop();
}
temp = ""; //表达式清空
while (!NStack.empty()) //数值栈清空
{
NStack.pop();
}
cout << "请输入多项式:";
cin >> str_in;
for (int i = 0; i < str_in.length(); i++)
{
if (str_in[i] >= '0' && str_in[i] <= '9') //处理数字
{
temp = str_in[i];
while (str_in[i + 1] >= '0' && str_in[i + 1] <= '9' && i<str_in.length())
{
temp += str_in[++i];
}
houzhuibiaodashi.push_back(temp); //数字推入后缀表达式
}
else if ((str_in[i] == '-' && i == 0) || (str_in[i] == '-'&& str_in[i - 1] == '(')) //处理负数,不能处理-(3+2)这种
{
temp = "";
temp = str_in[i++];
while (str_in[i] >= '0' && str_in[i] <= '9' && i<str_in.length())
{
temp += str_in[i];
i++;
}
houzhuibiaodashi.push_back(temp); //数字推入后缀表达式
}
if (str_in[i] == '(') //小括号直接入运算符栈
{
CStack.push(str_in[i]); //运算符入栈
}
else if (str_in[i] == ')')
{
temp = "";
while (!CStack.empty() && CStack.top() != '(')
{
temp = CStack.top();
houzhuibiaodashi.push_back(temp);
CStack.pop();
}
CStack.pop(); //(出栈
}
else if (str_in[i] == '+' || str_in[i] == '-' || str_in[i] == '*' || str_in[i] == '/')
{
temp = "";
if (str_in[i] == '+' || str_in[i] == '-')
{
while (!CStack.empty() && (CStack.top() == '+' || CStack.top() == '-' || CStack.top() == '*' || CStack.top() == '/'))
{
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
CStack.push(str_in[i]);
}
else if (str_in[i] == '*' || str_in[i] == '/')
{
while (!CStack.empty() && (CStack.top() == '*' || CStack.top() == '/'))
{
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
CStack.push(str_in[i]);
}
}
}
while (!CStack.empty())
{
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
/*完成后缀表达式,下边是李用后缀表达式求值*/
int i = 0;
float num1, num2;
while (!houzhuibiaodashi.empty() && i<houzhuibiaodashi.size())
{
if (houzhuibiaodashi[i] == "+")
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num1 + num2);
}
else if (houzhuibiaodashi[i] == "-")
{
if (i == 0) //检测到负号时可能是负数
{
char * data = new char[houzhuibiaodashi.size()];
for (int t = 1; t < houzhuibiaodashi[i].size(); t++)
{
data[t] = houzhuibiaodashi[i][t];
}
NStack.push(0 - atoi(data));
}
else
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num2 - num1);
}
}
else if (houzhuibiaodashi[i] == "*")
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num1 * num2);
}
else if (houzhuibiaodashi[i] == "/")
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num1 / num2);
}
else
{
char * data = new char[houzhuibiaodashi.size()];
for (int t = 0; t < houzhuibiaodashi[i].size(); t++)
{
data[t] = houzhuibiaodashi[i][t];
}
NStack.push(atoi(data));
}
i++;
}
cout << "等式的值为" <<NStack.top() << endl;
}
system("pause");
}
更新后的代码:
#include <Windows.h>
#include <iostream>
#include <vector>
#include <String>
#include <stack>
#include <cstdlib>
using namespace std;
/*
第一步,转换成后缀表达式
第二部,利用后缀表达式求解
如何转化为后缀表达式:
顺序扫描中序表达式
a) 是数字, 直接输出
b) 是运算符
i : “(” 直接入栈
ii : “)” 将符号栈中的元素依次出栈并输出, 直到 “(“, “(“只出栈, 不输出
iii: 其他符号, 将符号栈中的元素依次出栈并输出, 直到 遇到比当前符号优先级更低的符号或者”(“。 将当前符号入栈。
扫描完后, 将栈中剩余符号依次输出
*/
int main()
{
string str_in;
vector<string> houzhuibiaodashi; //后缀表达式
stack<char> CStack;
string temp; //临时
stack <float> NStack;
while (1)
{
houzhuibiaodashi.clear(); //后缀表达式向量清空
while (!CStack.empty()) //运算符栈清空
{
CStack.pop();
}
temp = ""; //表达式清空
while (!NStack.empty()) //数值栈清空
{
NStack.pop();
}
cout << "请输入多项式:";
cin >> str_in;
for (int i = 0; i < str_in.length(); i++)
{
if (str_in[i] == '(') //小括号直接入运算符栈
{
CStack.push(str_in[i]); //运算符入栈
}
else if (str_in[i] >= '0' && str_in[i] <= '9') //处理数字
{
temp = str_in[i];
while (str_in[i + 1] >= '0' && str_in[i + 1] <= '9' && i<str_in.length())
{
temp += str_in[++i];
}
houzhuibiaodashi.push_back(temp); //数字推入后缀表达式
}
else if (
(str_in[i] == '-'
&&( i > 0 && !(str_in[i-1] >= '0' && str_in[i-1] <= '9'&& str_in[i + 1] >= '0' && str_in[i + 1] <= '9')) //排除num-num型减法
&&( i > 0 && !(str_in[i - 1] == ')' && str_in[i + 1] >= '0' && str_in[i + 1] <= '9')) //排除()-num型减法
&&( i > 0 && !(str_in[i + 1] == ')' && str_in[i - 1] >= '0' && str_in[i - 1] <= '9'))) //排除num-()型减法
|| (str_in[i] == '-'&& i == 0) //加入负数在多项式开头的情况
)//处理负数,不能处理-(3+2)这种
{
temp = "";
temp = str_in[i++];
while (str_in[i] >= '0' && str_in[i] <= '9' && i<str_in.length())
{
temp += str_in[i];
i++;
}
houzhuibiaodashi.push_back(temp); //数字推入后缀表达式
i--; //防止指针过度移动。上一个版本的下一个分支直接用了if,不是else if , 虽然能解决这个问题但是不严谨
}
else if (str_in[i] == '-'&& str_in[i + 1] == '(' && (i == 0)) //处理-(3+2)在开头的多项式
{
houzhuibiaodashi.push_back("-1"); //改成-1 * (5+2) 进行计算,先压入-1,之后按照*规则处理
while (!CStack.empty() && (CStack.top() == '*' || CStack.top() == '/'))
{
temp = "";
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
CStack.push('*');
}
else if (str_in[i] == ')')
{
temp = "";
while (!CStack.empty() && CStack.top() != '(')
{
temp = "";
temp = CStack.top();
houzhuibiaodashi.push_back(temp);
CStack.pop();
}
CStack.pop(); //(出栈
}
else if (str_in[i] == '+' || str_in[i] == '-' || str_in[i] == '*' || str_in[i] == '/')
{
temp = "";
if (str_in[i] == '+' || str_in[i] == '-')
{
while (!CStack.empty() && (CStack.top() == '+' || CStack.top() == '-' || CStack.top() == '*' || CStack.top() == '/'))
{
temp = "";
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
CStack.push(str_in[i]);
}
else if (str_in[i] == '*' || str_in[i] == '/')
{
while (!CStack.empty() && (CStack.top() == '*' || CStack.top() == '/'))
{
temp = "";
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
CStack.push(str_in[i]);
}
}
}
while (!CStack.empty())
{
temp = CStack.top();
CStack.pop();
houzhuibiaodashi.push_back(temp);
}
/*完成后缀表达式,下边是李用后缀表达式求值*/
int i = 0;
float num1, num2;
while (!houzhuibiaodashi.empty() && i<houzhuibiaodashi.size())
{
if (houzhuibiaodashi[i] == "+")
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num1 + num2);
}
else if (houzhuibiaodashi[i] == "-")
{
if (i == 0) //检测到负号时可能是负数
{
char * data = new char[houzhuibiaodashi.size()];
for (int t = 1; t < houzhuibiaodashi[i].size(); t++)
{
data[t] = houzhuibiaodashi[i][t];
}
NStack.push(0 - atoi(data));
}
else
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num2 - num1);
}
}
else if (houzhuibiaodashi[i] == "*")
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num1 * num2);
}
else if (houzhuibiaodashi[i] == "/")
{
num1 = NStack.top();
NStack.pop();
num2 = NStack.top();
NStack.pop();
NStack.push(num2 / num1);
}
else
{
char * data = new char[houzhuibiaodashi.size()];
for (int t = 0; t < houzhuibiaodashi[i].size(); t++)
{
data[t] = houzhuibiaodashi[i][t];
}
NStack.push(atoi(data));
}
i++;
}
cout << "等式的值为" <<NStack.top() << endl;
}
system("pause");
}
代码更新说明:
上一个版本(就是划线的)简直bug百出,不能计算-(5+2)这种,除号和减号的运算规则也有错误。本次更新内容:
进一步优化判断条件;
修复了一些操作符bug;
完美支持加减乘除操作。
可自行加入乘方或者其他运算操作
第一步是将中缀表达式转换成后缀表达式。这一步很麻烦,用到的转换规则不是很好理解:
- 建立符号栈
- 顺序扫描中序表达式
a) 是数字, 直接输出 (即压入后缀表达式)
b) 是运算符
i : “(” 直接入栈 (压入运算符栈CStack)
ii : “)” 将符号栈中的元素依次出栈并输出(压入后缀表达式), 直到 “(“, “(“只出栈, 不输出
iii: 其他符号, 将符号栈中的元素依次出栈并输出, 直到 遇到比当前符号优先级更低的符号或者”(“。 将当前符号入栈。 - 扫描完后, 将栈中剩余符号依次输出
iii解释一下:举个例子,如果当前运算符栈中的内容是+,而当前的运算符是-,因为+不符合“比当前符号优先级低”的条件,所以需要将+弹栈并压入后缀表达式。之后栈为空,可以将-压入。也就是说,如果当前操作符是+、-,则一直弹栈,直到栈为空或者遇到“(”。如果当前操作符是*、/,则一直弹栈直到遇到+-或者“(”。
第二步是根据后缀表达式求值。很简单,从头读取后缀表达式,数字则压入数字栈,遇到操作符则从数字栈弹出相应数量数字进行运算(注意减法的减数和被减数不能搞错),运算结果压入数字栈。 最终,数字栈将只剩下一个数字,即为多项式运算结果。
附运行截图:
欢迎大家批评指正。