# 1. 分析
## 1.1 背景分析
如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题。任何一个表达式都是由操作数、操作符和分界符组成的。
算数表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表达式,即二元运算符位于两个运算数中间。为了正确执行这种中缀表达式的计算,必须明确各个操作符的执行顺序。为此每个操作符都规定了一个优先级。
C++ 规定,一个表达式中相邻的两个操作符的计算次序为:优先级高的先计算;如果优先级相同,则自左向右计算;当使用括号时,从最内层的括号开始计算。
由于中缀表达式中有操作符的优先级问题,还有可加括号改变运算顺序的问题,所以对于编译程序来说,一般不适用中缀表示处理表达式。解决办法是用后缀表示。
## 1.2 功能分析
作为能实现将中缀表达式转换为后缀表达式的程序,首先应能正确读入用户想要转换的中缀表达式(该中缀表达式是在一行中给出以空格分隔不同对象的中缀表达式,可包含 +-*/以及左右括号,表撒施不超过 20 个字符)。
之后可以根据相应的规则和各运算符的优先级正确无误的将中缀表达式转化为后缀表达式。
最后可以向用户输出转化好的后缀表达式(同时要求,在一行中输出转化后的后缀表达式,要求不同对象之间以空格分隔,但是结尾不得有多余空格)
# 2. 设计
## 2.1 数据结构设计
使用一个操作符栈用于表达式转换。
同时设定两个优先级,isp 是栈内优先数,icp 是栈外优先数,取值如下
```c++
int isp(char ch)
//栈内优先级
{
switch (ch)
{
case '#':
return 0;
case '(':
return 1;
case '*':
case '/':
return 5;
case '+':
case '-':
return 3;
case ')':
return 6;
}
}
int icp(char ch)
//栈外优先级
{
switch (ch)
{
case '#':
return 0;
case '(':
return 6;
case '*':
case '/':
return 4;
case '+':
case '-':
return 2;
case ')':
return 1;
}
}
```
左括号的栈外优先数最高,它一来到立即进栈,但当它进入栈中后,其栈内优先数变得极低,以便括号内的其他操作符进栈。其他操作符进入栈中后优先数都升 1,这样可体现在中缀表达式中相同优先级的操作符从左向右计算的要求,让位于栈顶的操作符先退栈听输出。操作符优先数相等的情况只出现在括号配对或栈顶的‘#’号与输入流最后的‘#’号配对时。前者将见徐退出位于栈顶的操作符,直到遇到左括号为止。然后将左括号退栈以对消括号,后者将结束算法。
## 2.2 类结构设计
设计表达式类,用于储存用户输入的中缀表达式和待输出的处理后的后缀表达式;同时维护操作符栈用于转换表达式。
## 2.3 成员与操作设计
表达式类(Express)
私有成员:
```c++
string _express; //储存中序表达式
int _current = 0; //表达式的定位变量
string _next; //下一个内容
string _result; //储存后缀表达式
stack<char> OpCode; //操作符栈
```
表达式类的构造函数:
```c++
Express() = default;
Express(string &buf);
Express::Express(string & buf)
//对表达式进行一些处理,在结尾添加下面内容用于判断终止
:_express(buf)
{
_express.push_back(' ');
_express.push_back('#');
_express.push_back(' ');
}
```
公有操作:
```c++
void NextContent(); //寻找下一个对象
void Change(); //将中序表达式转化为后续表达式
void ShowResult(); //输出结果(结尾不能有空格)
```
## 2.4 系统设计
系统首先读入用户输入的中缀表达式,并构建以该表达式为基础的表达式类,之后调用相应的算法将中缀表达式转换为后缀表达式。最后按照正确的格式输出后缀表达式。
# 3. 实现
## 3.1 表达式转换功能的实现
### 3.1.1 表达式转换功能流程图
![](https://www.writebug.com/myres/static/uploads/2022/8/15/d9d01a833380fe65f01b98e433ea421f.writebug)
### 3.1.2 表达式转换功能核心代码
```c++
void Express::Change()
{
OpCode.push('#'); //操作符栈初始化,将结束符#进栈
NextContent(); //读入中缀表达式字符流的首字符
while (!OpCode.empty())
//循环做, 直到ch=='#', 同时栈顶的操作符也是'#', 停止循环
{
char ch = _next[0];
if (MyisNum(_next)) //如果是操作数, 直接读入下一个字符
{
_result.append(_next); //添加到结果当中
_result.push_back(' ');
NextContent();
}
else if (ispunct(ch)) //如果是操作符, 判断ch的优先级icp和当前栈顶操作符的优先级isp
{
char topch = OpCode.top();
if (isp(topch) < icp(ch)) //当前操作符优先级大,另ch进栈,读入下一个字符
{
OpCode.push(ch);
NextContent();
}
else if (isp(topch) > icp(ch)) //当前优先级小,退栈并输出到结果中
{
_result.push_back(OpCode.top());
_result.push_back(' ');
OpCode.pop();
}
else
{
if (OpCode.top() == '(') //如果退出的是左括号则读入下一个字符
{
NextContent();
}
OpCode.pop();
}
}
}
}
```
### 3.1.3 表达式转换功能截屏示例
![](https://www.writebug.com/myres/static/uploads/2022/8/15/8a17dcdbd556afbf897a34404e6228bd.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/8/15/a9c6eeb8a371c858a99bcc6cf5e87ffa.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/8/15/fe24e897e9a2f689ef290aadba4a574f.writebug)
## 3.2 输出后缀表达式功能的实现
### 3.2.1 输出后缀表达式功能流程图
![](https://www.writebug.com/myres/static/uploads/2022/8/15/4ca4694a2ebd6db95a433c3c5612a237.writebug)
### 3.2.2 输出后缀表达式功能核心代码
```c++
void Express::ShowResult()
//结尾空格不输出
{
for (char *pch = &_result[0]; pch < &_result[0] + _result.size() - 1; ++pch)
{
cout << *pch;
}
}
```
### 3.2.3 输出后缀表达式功能截屏示例
![](https://www.writebug.com/myres/static/uploads/2022/8/15/949de3ddf75bf44db84694a7be620580.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/8/15/929c63e9ce6c0eec2ca95dcb7b84f5ac.writebug)
![](https://www.writebug.com/myres/static/uploads/2022/8/15/70656a055d9e95d61a1963256f17486e.writebug)
## 3.3 取下一元素功能的实现
### 3.3.1 取下一元素功能流程图
![](https://www.writebug.com/myres/static/uploads/2022/8/15/505ae05ef55d0b5bfabf2bc28fb438a0.writebug)
### 3.3.2 取下一元素功能核心代码
```c++
void Express::NextContent()
{
_next.clear(); //每次找下一个内容先把_next清空
char ch;
for (int i = _current; i < this->_express.size(); ++i)
{
ch = _express[i];
if (!isspace(ch))
{
_next.push_back(ch);
//因为不同对象以空格隔开,所以只要不是空格就加到_next
}
else
{
_current = i + 1; //_current指向下一个位置,结束当前对象的寻找
break;
}
}
}
```
### 3.3.3 取下一元素功能截图示例
![](https://www.writebug.
shejizuopin
- 粉丝: 1w+
- 资源: 1300
最新资源
- bdwptqmxgj11.zip
- onnxruntime-win-x86
- onnxruntime-win-x64-gpu-1.20.1.zip
- vs2019 c++20 语法规范 头文件 <ratio> 的源码阅读与注释,处理分数的存储,加减乘除,以及大小比较等运算
- 首次尝试使用 Win,DirectX C++ 中的形状渲染套件.zip
- 预乘混合模式是一种用途广泛的三合一混合模式 它已经存在很长时间了,但似乎每隔几年就会被重新发现 该项目包括使用预乘 alpha 的描述,示例和工具 .zip
- 项目描述 DirectX 引擎支持版本 9、10、11 库 Microsoft SDK 功能相机视图、照明、加载网格、动画、蒙皮、层次结构界面、动画控制器、网格容器、碰撞系统 .zip
- 项目 wiki 文档中使用的代码教程的源代码库.zip
- 面向对象的通用GUI框架.zip
- 基于Java语言的PlayerBase游戏角色设计源码
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈