任何一个表达式都可以看成是三部分组成,操作数、运算符和界限定符组成。我们平时的表达式都是:中缀表达式,——即运算符在两个操作数之间。然而这种算式放在计算机中是无法计算的,因为不同的运算符的优先级是不同的,如果按中缀表达式计算时,处理起来就会非常麻烦,所以当计算机运算时一般是将中缀表达式转为后缀表达式进行计算的。后缀表达式的好处在于不需要考虑各个符号的优先级。因为在后缀表达式中的符号都是按优先级排好的,所以在计算时,就不需要考虑这些问题。这就大大简化了计算的复杂度。下面举个例子展示后缀表达式如何计算:
中缀表达式:a/b-(c+d*e)*f
对应的后缀表达式为:ab/cde*+f*-
从左向右扫描后缀表达式,
(1)如果是数字,入栈。
(2)如果是符号,弹出栈顶的两个操作数,进行计算,将结果入栈。
演示过程:
原谅画功有限。
现在计算这个表达式结果的算法很好写。这里需要注意:
因为后缀表达式的操作数可能在一起,当数据为多位时如何区分。
这时我们就需要用到定界符,可以在两个操作数的之间设置空格,作为区分。
现在的问题就转化为如何使用中缀表达式得到后缀表达式。
首先我们为每个运算符定义优先级:
运算符:( + - * /
优先数: 0 1 1 2 2
从左向右扫描中缀表达式:
(*此时输入的仅仅只是一个字符串,设置运算符栈。)
(1)如果字符串结束,将从栈顶起的运算符依次出栈,发给后缀表达式。
(2)如果是操作数直接发给后缀表达式。
(3)如果是运算符,且优先级大于栈顶元素,进栈,否则将栈中优先级大于等于当前运算符的依次出栈发给后缀表达式,再进栈。但如果是“(“则直接进栈。
(4)如果是”)“将栈顶元素依次发给后缀表达式,直到栈顶元素为”(“,将”(“出栈。
*()不入后缀表达式。
接下来我们使用代码实现这两个功能。
首先我们需要栈,用来存放后缀表达式和计算后缀表达式是使用。当然这里可以使用STL中的Stack()。由于是联系栈结构所以这里自己写了一个栈。
//文件为:StackList.h
#pragma once
#include<iostream>
using namespace std;
class StackList
{
private:
char Operator;
StackList* Next;
//记录栈中元素个数
static int Count;
public:
StackList* InitStackList();
char PopStack(StackList* Head);
void InsertStack(StackList* Head, char Operator);
void DestructionStack(StackList* Head);
//判断栈是否为空
static bool StackEmpty(StackList* Head);
//查看栈顶元素
char StackTop(StackList* Head);
};
//文件为:StackList.cpp
#include "StackList.h"
int StackList::Count = 0;
StackList* StackList::InitStackList()
{
StackList* Head = new StackList();
if (Head == NULL)
{
cout << "内存没有申请成功" << endl;
exit(1);
}
else
{
Head->Next = NULL;
return Head;
}
}
char StackList::PopStack(StackList* Head)
{
StackList* p = Head->Next;
if (p != NULL)
{
char ch = p->Operator;
if (Count != 1)
{
Head->Next = p->Next;
}
delete p;
p = NULL;
--Count;
//cout << "剩余元素个数" << Count << endl;
return ch;
}
}
void StackList::InsertStack(StackList* Head, char Operator)
{
StackList* p = new StackList();
p->Operator = Operator;
if (Head->Next==NULL)
{
Head->Next = p;
p->Next = NULL;
}
else
{
p->Next = Head->Next;
Head->Next = p;
}
++Count;
}
bool StackList::StackEmpty(StackList* Head)
{
bool bref = false;
if (Count == 0)
{
bref = true;
}
return bref;
}
char StackList::StackTop(StackList* Head)
{
if (Head->Next != NULL)
{
StackList* p = Head->Next;
return p->Operator;
}
}
将中缀表达式转化为后缀表达式:
//文件:PostfixExpression.h
#pragma once
#include<string>
#include"StackList.h"
class PostfixExpression
{
private:
//中缀
string Expression;
//后缀
string pPostfix;
//符号栈
StackList Operator;
//符号栈的头节点
StackList* pOperator;
//运算符的优先级
int OperatorPriority(char ch);
public:
//初始化字符串
PostfixExpression(const string& Airth);
//将中缀表达式转化为后缀表达式
void ChangeForPostfixExpression();
string GetPostfixExpression();
};
计算后缀表达式:
//文件:Calculate.h
#pragma once
#include"PostfixExpression.h"
//计算后缀表达式
class Calculate
{
private:
string pPostfix;
PostfixExpression Expression;
public:
Calculate(string expression);
//将后缀表达式标准化。去除字符串的前面的空格,把字符串的空格调整成一个。空格的作用为分隔数字,只留一个。
void SpecificationExpression();
void ShowPostfixExpression();
int Calc();
};
//文件:Calculate.cpp
#include "Calculate.h"
#include<vector>
Calculate::Calculate(string expression)
:Expression(expression)
{
pPostfix = Expression.GetPostfixExpression();
SpecificationExpression();
}
int Calculate::Calc()
{
vector<int> num;
int i = 0, sum = 0, num1 = 0, num2 = 0, num3 = 0, len = pPostfix.length();
while (i != len)
{
if (pPostfix[i] >= '0'&&pPostfix[i] <= '9')
{
sum = sum * 10 + (pPostfix[i] - '0');
}
else if (pPostfix[i] == ' ')
{
num.push_back(sum);
if (pPostfix[i + 1] == ' ')
{
++i;
}
sum = 0;
}
else
{
num1 = num.back();
num.pop_back();
num2 = num.back();
num.pop_back();
switch (pPostfix[i])
{
case '+':
num3 = num2 + num1;
break;
case '-':
num3 = num2 - num1;
break;
case '*':
num3 = num2 * num1;
break;
case '/':
num3 = num2 / num1;
break;
}
num.push_back(num3);
if (pPostfix[i + 1] == ' ')
{
++i;
}
}
++i;
}
return num.back();
}
void Calculate::ShowPostfixExpression()
{
cout << pPostfix << endl;
}
void Calculate::SpecificationExpression()
{
int i = 0, len = 0;
len = pPostfix.length();
while (i < len)
{
if (pPostfix[i] == ' '&&pPostfix[i + 1] == ' ')
{
pPostfix.replace(i, 1, "");
//替换之后后面的字符会自动补上
--i;
}
len = pPostfix.length();
++i;
}
if (pPostfix[0] == ' ')
{
pPostfix.replace(0, 1, "");
}
}
//文件:主函数
#include"Calculate.h"
int main()
{
string Expression;
cout << "请输入需要计算的算式:" << endl;
cin >> Expression;
//传给计算类的表达式必须是对的。
Calculate Calc(Expression);
cout << "后缀表达式为:" << endl;
Calc.ShowPostfixExpression();
cout << "计算结果为:" << Calc.Calc() << endl;
return 0;
}
//InitExproess.h
#pragma once
#include<string>
using namespace std;
class InitExproess
{
public:
InitExproess();
~InitExproess();
bool JudgeOperator(char Exp);
void StringReplace(string& Ari);
};
//InitExproess.cpp
#include "InitExproess.h"
InitExproess::InitExproess()
{
}
InitExproess::~InitExproess()
{
}
bool InitExproess::JudgeOperator(char Exp)
{
bool bref = false;
if (Exp == '+' || Exp == '-' || Exp == '*' || Exp == '/')
{
bref = true;
}
return bref;
}
void InitExproess::StringReplace(string& Ari)
{
//将符号进行处理
int i = 0, len = Ari.length();
if (Ari[0] == '+')
{
Ari.replace(0, 1, "");
}
while (i < len)
{
if (Ari[i] == '-' && (i == 0 || JudgeOperator(Ari[i - 1]) || Ari[i - 1] == '('))
{
Ari.replace(i, 1, "(1-2)*");
//替换之后子符串长度会发生改变,需要更新len的值。
len = Ari.length();
}
++i;
}
}
主要实现的是表达式转为后缀和如何计算。检查表达式是否合法的算法没有实现。
*因为符号中没有处理“-“号,所以在中缀转后缀是我们时将负号处理为了(1-2)*。
结果展示: