一、实验题目及要求
题目:表达式的后缀表示
表达式中包含运算对象、运算符和圆括号等,习惯上使用中缀表示(指运算符夹在两运算符对象中间)形式。计算表达式的值,涉及到运算符的优先级别,如先乘除后加减。括在一对圆括号中的子表达式必须先计算,因此,圆括号可视为特殊的运算符,具有最高优先级别。圆括号可以任意嵌套,这意味着左圆括号后面又是表达式,形成表达式的递归定义。为了直接指明表达式中各运算对象的先后计算顺序,可将表达式的中缀形式转换成后缀(指运算符放在二运算对象的后面)形式。例如,表达式a*b-(c+d)/e,这是通常的中缀形式,其后缀表示是ab*cd+e/-,其中圆括号在后缀形式中已不见了。
设计一转换程序,将输入的任一表达式转换成相应的后缀形式后输出。
二、需求分析
在转换过程中,要求作必要的语法检查,例如圆括号是否配对,单词是否合法等。
三、概要设计
考虑用栈实现。
1、用string类型的对象存储输入的中缀表达式;
2、从0位置开始判断字符,如果是数字,那就要判断后面是否是数字,如果是就不断扫描组成一个整数,最终组成一个整数,然后输出这个数;
3、如果是左括号,直接进栈;
4、如果是操作运算符,与栈顶元素比较优先级,如果高就压入栈;如果低,就取出栈顶元素输出;接着,栈顶元素和当前运算符号继续比较优先级,重复前面步骤,直到栈空或者当前的符号优先级高;
5、如果是右括号,把栈顶的元素取出,如果不是左括号,把取出的运算符输出,接着取栈顶的元素,直到栈中取出的符号是左括号;
6、扫描完成后,判断栈是否为空,若不为空,把符栈顶的元素取出并输出,直到栈空为止。
四、测试结果
五、源代码
stack.h
#ifndef STACK_H_
#define STACK_H_
#include <iostream>
using namespace std;
template<class T>
class stack {
public:
stack();
~stack();
void push(T t);//压栈
T top();//取栈顶元素
T pop();//出栈
int size();//大小
int isEmpty();//判断栈是否为空
private:
T* arr;
int count;
};
//构造
template<class T>
stack<T>::stack()
{
arr = new T[100];
if (!arr)
{cout << "出错" << endl;}
}
//析构
template<class T>
stack<T>::~stack() {
if (arr) {
delete[] arr;
arr = NULL;
}
}
//向栈中添加一个元素
template<class T>
void stack<T>::push(T t)
{arr[count++] = t;}
//取栈顶元素
template<class T>
T stack<T>::top()
{return arr[count - 1];}
// 返回栈顶元素并删除
template<class T>
T stack<T>::pop()
{
int ret = arr[count - 1];
count--;
return ret;
}
// 返回栈的大小
template<class T>
int stack<T>::size()
{
return count;
}
//判断栈是否为空
template<class T>
int stack<T>::isEmpty() {
return size() == 0;
}
#endif
ReversePolish.cpp
//求逆波兰表达式(非递归版本)
#include <iostream>
#include<string>
#include"stack.h"
using namespace std;
// 判断是否是操作符
int isOperator(char ch) {
if (ch == '+' || ch == '-' || ch == '*' || ch == '/')
return 0;
if (ch == '(' || ch == ')')
return 1;
return 2;
}
//获取优先级
int priority(char ch) {
int level = 0; //优先级
switch (ch) {
case '(':
level = 1;
break;
case '+':
case '-':
level = 2;
break;
case '*':
case '/':
level = 3;
break;
default:
break;
}
return level;
}
bool Rational(string str)//判断输入的表达式的合理性
{
int temp = 0;
if (str[0] == '/' || str[0] == '*' || str[0] == '+' || str[0] == '-')//以运算符开头
return false;
for (int i = 0; i < str.length(); i++)
{
if (i < str.length() - 1)
{
if (isOperator(str[i])==0&&isOperator(str[i + 1])==0) return false;
}
if (i < str.length() - 1)
{
if (str[i] == '(')//检查左右括号是否匹配
{
if (str[i + 1] == '*' || str[i + 1] == '/' || str[i + 1] == '-' || str[i + 1] == '+')
return false;//左括号后不能是运算符
temp++;
}
}
if (str[i] == ')')
{
if (i == 0)
return false;
if (str[i - 1] == '+' || str[i - 1] == '*' || str[i - 1] == '-' || str[i - 1] == '/')
return false;//右括号前不能是运算符
temp--;
}
}
if (temp == 0)
return true;
else
return false;
}
int main()
{
int num;
string s;
stack<char> op; // 栈op:存储操作符
while(1) {
cout << "请输入中缀表达式:" << endl;
cin >> s;
if (Rational(s) == false)
{
cout << "表达式不合理,请重新输入!" << endl;
exit(0);
}
cout << "后缀表达式为:" << endl;
int len, i;
char c; // c存储从栈中取出的操作符
len = (int)(s.length());
i = 0;
while (i < len) {
if (isOperator(s[i])==2) {
num = 0;
do {
cout << s[i];
i++;
} while (isdigit(s[i]));
cout << " ";
}
else if (s[i] == '(') { // 左括号
op.push(s[i]);
i++;
}
else if (isOperator(s[i])==0) { //操作符
if (op.isEmpty()) { //如果栈空,直接压入栈
op.push(s[i]);
i++;
}
else {
// 比较栈op顶的操作符与ch的优先级
// 如果ch的优先级高,则直接压入栈
// 否则推出栈中的操作符,直到操作符小于ch的优先级,或者遇到(,或者栈已空
while (!op.isEmpty()) {
c = op.top();
if (priority(s[i]) <= priority(c)) {
// 优先级低或等于
cout << c << " ";
op.pop();
}
else // ch优先级高于栈中操作符
break;
} // while结束
op.push(s[i]); // 防止不断的推出操作符,最后空栈了;或者ch优先级高了
i++;
}
}
else if (s[i] == ')') {
// 如果是右括号,一直推出栈中操作符,直到遇到左括号(
while (op.top() != '(') {
cout << op.top() << " ";
op.pop();
}
op.pop(); //把左括号推出栈
i++;
}
else // 如果是空白符,就进行下一个字符的处理
i++;
}
while (!op.isEmpty()) { // 当栈不空,继续输出操作符
cout << op.top() <<" ";
op.pop();
}
cout << std::endl;
}
return 0;
}