鉴于以前在CSDN也获得了前辈们的许多帮助,这里也发布一篇实验的代码文章
实验项目1:栈结构及其应用
实验题目:算术表达式求值(算术计算器)
实验内容:
表达式求值是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。假设操作数是正整数,运算符只含加减乘除等四种二元运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。引入表达式起始、结束符是为了方便。设计一个程序,演示算术表达式求值的过程。
实验要求:
- 从文本文件输入任意一个语法正确的(中缀)表达式,显示并保存该表达式。
- 利用栈结构,把(中缀)表达式转换成后缀表达式,并以适当的方式展示栈的状态变化过程和所得到的后缀表达式。
- 利用栈结构,对后缀表达式进行求值,并以适当的方式展示栈的状态变化过程和最终结果。
运行结果截图:
注:程序中运用了to_string函数,所以需要在c++11及以上环境中运行
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
struct node {
string data;
node* next;
};
typedef node* STACK;
void Getstr_done(char str[], char str_done[]);
bool Check(char str[]);
int pri(char op);
STACK MakeNull();
string Tostring(char x);
void Pop(STACK S);
void Push(string x, STACK S);
string Top(STACK S);
void PrintSTACK(STACK S);
void Print(string b);
bool IsEmpty(STACK S);
string GetArith(char a[], string b, STACK S);
void Colc(string Arith, STACK S);
int IsMulti(char str[], int x);
int main(){
cout << "1.以#开头和结束"<<endl;
cout << "2.表达式中不含其他字符"<<endl;
cout << "3.只进行正整数(int)间的运算"<<endl;
cout << "----------------------" <<endl;
cout << "请输入中缀表达式:" <<endl;
char str[200]; //储存最初的中缀表达式(包含#)
cin >> str;
char str_done[strlen(str)-2]; //储存开始符与结束符中的中缀表达式
string Arith; //储存生成的后缀表达式
if (Check(str) == 0){
cout << "输入错误!" <<endl;
return 0;
}
else {
Getstr_done(str, str_done);
STACK S;
S = MakeNull();
Arith = GetArith(str_done, Arith, S);
cout << "得到后缀表达式:"<<endl;
cout<<Arith<<endl;
S = MakeNull();
cout << "开始计算后缀表达式:"<<endl;
Colc(Arith, S);
return 0;
}
}
void Getstr_done(char str[], char str_done[]){ //取得开始符与结束符中的中缀表达式
for (int i=0; i<strlen(str)-1; i++){
str_done[i] = str[i+1];
}
str_done[strlen(str)-2] = '\0'; //结尾加上结束符
cout << "提取中缀表达式:" <<endl;
cout << str_done <<endl;
cout << "----------------------" <<endl;
}
bool Check(char str[]){ //检查表达式输入合法性
if (str[0] != '#' || str[strlen(str)-1] != '#') return false;
for (int i=0; i<strlen(str); i++){
if (!((str[i]>=48 && str[i]<=57) || (str[i]!='(') || (str[i]!=')') || (str[i]!='+') || (str[i]!='-') || (str[i]!='*') || (str[i]!='/')))
return false;
}
return true;
}
string GetArith(char str_done[],string Arith, STACK S){ //中缀转后缀,后缀存为string
for (int i=0; i<strlen(str_done); i++){
if (pri(str_done[i]) == 3){ //数字情况
if (IsMulti(str_done, i)){ //若某位字符是多位数中间的数字,则后缀表达式不加空格
Arith += str_done[i];
PrintSTACK(S);
Print(Arith);
}
else{
Arith += str_done[i];
Arith += " ";
PrintSTACK(S);
Print(Arith);
}
}
else //非数字情况
{
//栈空直接入栈
if(IsEmpty(S) == 1){
Push(Tostring(str_done[i]), S);
PrintSTACK(S);
Print(Arith);
}
//左括号直接入栈
else if(str_done[i] == '('){
Push(Tostring(str_done[i]), S);
PrintSTACK(S);
Print(Arith);
}
//右括号按要求弹出
else if(str_done[i] == ')')
{
while(Top(S)[0] != '(')
{
Arith += Top(S)[0];
Arith += " ";
Pop(S);
}
//弹出左括号,但不输出
Pop(S);
PrintSTACK(S);
Print(Arith);
}
else{
//优先级弹出
while(pri(str_done[i]) <= pri(Top(S)[0])){ //Top(S)[0]指字符串中的首元素
Arith += Top(S)[0];
Arith += " ";
Pop(S);
//栈空停止
if(IsEmpty(S) == 1) break;
}
Push(Tostring(str_done[i]), S);
}
}
cout << "----------------------" <<endl;
}
while (IsEmpty(S) != 1){ //最终清空栈内运算符
Arith += Top(S)[0];
Arith += " ";
Pop(S);
PrintSTACK(S);
Print(Arith);
cout << "----------------------" <<endl;
}
return Arith;
}
void Colc(string Arith, STACK S){ //由后缀表达式计算结果
for (int i=0; i<Arith.length(); i++){
if (pri(Arith[i]) == 3){
string tmp; //将数字以字符串形式存在栈中
for (int j=i; j<Arith.length(); j++){
tmp += Arith[j];
if (pri(Arith[j+1]) == 3) continue; //多位数数字持续读取到末尾
else{
Push(tmp, S); //数字入栈
i = j+1;
break;
}
}
PrintSTACK(S);
}
if (Arith[i] == ' ') continue; //空格直接跳过
else if (Arith[i] == '+'){
float a = atof(Top(S).c_str());
Pop(S);
float b = atof(Top(S).c_str());
Pop(S);
float c = (float)b+(float)a;
Push(to_string(c), S);
PrintSTACK(S);
}
else if (Arith[i] == '-'){
float a = atof(Top(S).c_str());
Pop(S);
float b = atof(Top(S).c_str());
Pop(S);
float c = (float)b-(float)a;
Push(to_string(c), S);
PrintSTACK(S);
}
else if (Arith[i] == '*'){
float a = atof(Top(S).c_str());
Pop(S);
float b = atof(Top(S).c_str());
Pop(S);
float c = (float)b*(float)a;
Push(to_string(c), S);
PrintSTACK(S);
}
else if (Arith[i] == '/'){
float a = atof(Top(S).c_str());
Pop(S);
float b = atof(Top(S).c_str());
Pop(S);
float c = (float)b/(float)a;
Push(to_string(c), S);
PrintSTACK(S);
}
}
cout << "最终结果:" << Top(S) <<endl;
}
int pri(char op){ //符号优先级
int pri;
if(op >= 48 && op <= 57) pri = 3;
if(op == '*' || op == '/') pri = 2;
if(op == '+' || op == '-') pri = 1;
if(op == '(') pri = 0;
if(op ==')' || op == '#') pri = 4; //此处将两者定义防止出bug
return pri;
}
STACK MakeNull(){
STACK S = new node;
S->next = NULL;
return S;
}
void Pop(STACK S){
STACK stk;
if (S->next){
stk = S->next;
S->next = stk->next;
delete stk;
}
}
void Push(string x, STACK S){
STACK stk;
stk = new node;
stk->data = x;
stk->next = S->next;
S->next = stk;
}
void PrintSTACK(STACK S){
node* L = S -> next;
cout << "栈:" <<endl;
while (L!=NULL){
cout << L->data << " ";
L = L->next;
}
cout <<endl;
}
string Top(STACK S){ //返回栈顶元素的data值
if (S->next != NULL){
return S->next->data;
}
else return 0;
}
void Print(string Arith){
cout << "后缀表达式: ";
cout << Arith <<endl;
}
bool IsEmpty(STACK S){
if (S->next == NULL) return true;
else return false;
}
string Tostring(char x){ //将char转换为string,便于后缀表达式的多位数计算
string s;
s.append(1, x);
return s;
}
int IsMulti(char str[], int x){ //判断多位数,若为多位数的中间数字,则输出1,代表不加空格。否则输出0,代表加空格
if (pri(str[x]) == 3 && x == strlen(str)-1) return 0; //若表达式最后一个字符是数字,则输出0,在此数字后加空格
if (pri(str[x]) != 3) return 0; //若不是数字,直接加空格
else if (pri(str[x]) == 3 && pri(str[x+1]) == 3) return 1; //是多位数中间的数字,输出1,不加空格
return 0;
}