
大家好,我是不会写开场白的AYAKA。
今天我们先来复习一下中缀表达式、前缀表达式和后缀表达式,以及如何用栈来实现它们之间的运算。
一、中缀表达式
中缀表达式是一种算术或逻辑公式的表示方法,其中操作符位于操作数的中间。举个例子就懂了:例如“3 + 4”、“114514*1919810”都是中缀表达式。
然而,对于计算机来说,处理中缀表达式相对复杂,因为计算机更擅长处理前缀或后缀表达式。
二、前缀表达式
①这是?
前缀表达式,也称为波兰表达式,是一种算术或逻辑公式的表示方法,其中操作符位于操作数之前。例如,中缀表达式3 + 4 * 5
转换成前缀表达式即为+ 3 * 4 5
。
前缀表达式的主要特点是去掉了中缀表达式中用于明确运算顺序的括号,通过运算符的位置直接表明运算的优先级和顺序。这种表示方式使得表达式的计算过程更加简洁和直观(当然,这是对计算机来说)。
前缀表达式在计算机科学中主要用于算法设计和实现,特别是在需要高效处理大量数学运算的场景中。例如,在编译器的设计中,前缀表达式可以帮助简化表达式的解析和计算过程。
②转前缀表达式
中缀表达式转前缀表达式有很多种方法,其中一种简单的方法就是添加括号法。
主要分成三个步骤进行:
-
1.根据运算符的优先级对中缀表达式加括号,将优先级高的运算符放在括号内
-
2.将运算符移到对应的括号前面
-
3.去掉所有括号
例如,中缀表达式82 + 3 * (20 - 8) / 2
转换成前缀表达式为+ 82 * 3 / - 20 8 2
。
文字表达大家可能不太理解,我这里用一张图片来解释:
③计算过程
前缀表达式在计算过程中主要分成四步来进行:
1.从右到左
遍历表达式;
2.遇到数字就进栈;
3.遇到符号,就将栈顶元素出栈作为第一操作数
,接着将新的栈顶元素出栈作为第二操作数
,进行运算,然后将结果进栈;
4.重复以上操作直到表达式遍历结束,栈中的元素就是结果。
对于第一操作数和第二操作数是什么这个问题,一张图片就能解释了:
计算过程我来详细解释下:
我们以前缀表达式- 1 * + 3 4 5
为例:
首先,我们从右往左,先将数字5入栈,接着将数字4入栈,最后将数字3入栈。
我们遇到操作符+,出栈,将栈顶元素3出栈作为第一操作数
,接着将新的栈顶元素4出栈作为第二操作数
,3 + 4 = 7,然后将结果7进栈。
接着,我们将符号*出栈,将栈顶元素7出栈作为第一操作数
,接着将新的栈顶元素5出栈作为第二操作数
,7 * 5 = 35,与遇到的数字1同时进栈。
最后,我们遇到操作符-,将目前栈顶元素1出栈作为第一操作数
,接着将新的栈顶元素35出栈作为第二操作数
,1 - 35 = -34,然后将结果-34进栈。
最终,我们得到答案-34.
三、后缀表达式
①这是?
后缀表达式,也称为逆波兰表达式,是一种算术或逻辑公式的表示方法,其中操作符位于操作数之后。还是同一个例子:中缀表达式中3 + 4 * 5
转换成后缀表达式为3 4 5 * +
。
它简化了表达式的解析和计算过程,去掉了中缀表达式中用于明确运算顺序的括号,通过运算符的位置直接表明运算的优先级和顺序。这种表示方式也使得表达式的计算过程更加简洁和直观。
②转后缀表达式
同样分成三个步骤进行:
-
1.根据运算符的优先级对中缀表达式加括号,将优先级高的运算符放在括号内
-
2.将运算符移到对应的括号后面
-
3.去掉所有括号
同一个例子,中缀表达式82 + 3 * (20 - 8) / 2
转换成后缀表达式为82 3 20 8 - * 2 / +
。
③计算过程
当然,后缀表达式在计算过程中也主要分成四步来进行:
1.从左到右
遍历表达式;
2.遇到数字就进栈;
3.遇到符号,就将栈顶元素出栈作为第二操作数
,接着将新的栈顶元素出栈作为第一操作数
,进行运算,然后将结果进栈;
4.重复以上操作直到表达式遍历结束,栈中的元素就是结果。
大家可能还不是很理解,我再来详细解释下:
我们以后缀表达式82 3 20 8 - * 2 / +
为例:
首先,我们从左到右,先将数字82入栈,接着将数字3入栈,然后将数字20入栈,最后将数字8入栈。
我们遇到操作符-,出栈,将栈顶元素8出栈作为第二操作数
,接着将新的栈顶元素20出栈作为第一操作数
,20 - 8 = 12,然后将结果12进栈。
接着,我们将符号*出栈,将栈顶元素12出栈作为第二操作数
,接着将新的栈顶元素3出栈作为第一操作数
,3 * 12 = 36,然后将结果36进栈。
然后,我们将数字2入栈,遇到符号/出栈,将栈顶元素2出栈作为第二操作数
,接着将新的栈顶元素36出栈作为第一操作数
,36 / 2 = 18,然后将结果18进栈。
最后,我们遇到操作符+,将目前栈顶元素18出栈作为第二操作数
,接着将新的栈顶元素82出栈作为第一操作数
,82 + 18 = 100,然后将结果100进栈。
最终,我们得到答案100.
现在,我们已经了解了前、中、后缀表达式,以及它们之间的计算。接下来,我们就用代码来实现它们之间的运算。
四、代码解决前、后缀表达式运算
①数组模拟
首先,我们可以用数组来模拟栈,来实现前缀表达式和后缀表达式的运算。缺点就是,数组模拟栈的效率较低,且代码较多,不好理解。
代码……开写!
转前缀表达式
#include <iostream>#include <string>#include <cmath>using namespace std;
int st[n+1]; // int数组模拟栈int TOP = 0; // 栈顶指针初始化(归0)
void push(int x)//入栈操作{ TOP++; st[TOP] = x;}
void pop( ) //出栈操作{ TOP--;}
int top( ) // 获取栈顶元素{ return st[TOP];}
int main(){ string a; getline(cin, a);
for (int i = a.length() - 1; i >= 0; i--) { // 初始化sum和idx来构建数字 int sum = 0, idx = 0; // 当当前字符是数字时,构建数字 while (a[i] >= '0' && a[i] <= '9') { sum = sum + (a[i] - '0') * pow(10, idx); idx++; i--; // 递减i以继续检查前一个字符 }
if (sum != 0) // 如果遇到符号,则将其推入栈中 { push(sum); }
// 如果当前字符是运算符,则处理运算符 if (a[i] == '+' || a[i] == '-' || a[i] == '*' || a[i] == '/') { int num1 = top(); pop(); // 弹出栈顶元素 int num2 = top(); pop(); // 加、减、乘、除运算: if (a[i] == '+') push(num2 + num1); else if (a[i] == '-') push(num2 - num1); else if (a[i] == '*') push(num2 * num1); else if (a[i] == '/') push(num2 / num1); } }
cout << top(); return 0;}
转后缀表达式
// 部分逻辑同上#include <iostream>#include <string>#include <cmath>using namespace std;
int st[n+1]; // int数组模拟栈int TOP = 0; // 栈顶指针初始化(归0)
void push(int x)//入栈操作{ TOP++; st[TOP] = x;}
void pop( ) //出栈操作{ TOP--;}
int top( ) // 获取栈顶元素{ return st[TOP];}
int main(){ string a; getline(cin, a);
for (int i = 0; i < a.length() - 1; i++) { // 初始化sum来构建数字 int sum = 0; // 当当前字符是数字时,构建数字 while (a[i] >= '0' && a[i] <= '9') { sum = sum * 10 + (a[i] - '0'); i++; }
if (sum != 0) { push(sum); }
if (a[i] == '+' || a[i] == '-' || a[i] == '*' || a[i] == '/') { int num2 = top(); pop(); int num1 = top(); pop(); if (a[i] == '+') push(num1 + num2); else if (a[i] == '-') push(num1 - num2); else if (a[i] == '*') push(num1 * num2); else if (a[i] == '/') push(num1 / num2); } }
cout << top(); return 0;}
②标准模板库(STL)模拟
上篇文章,我们简单认识了标准模板库(STL),在模拟栈中更加方便。那么,我们今天就来用STL来实现一下前缀表达式和后缀表达式的运算。
主要核心不变,只是相关函数更改而已。代码如下:
转前缀表达式
#include <iostream>#include <string>#include <stack> // 今天的主角#include <cmath>using namespace std;
int main(){ stack <int> s; // 格式就是这样,别写错了 string a; getline(cin, a);
for (int i = a.length() - 1; i >= 0; i--) { // 初始化sum和idx来构建数字 int sum = 0, idx = 0; // 当当前字符是数字时,构建数字 while (a[i] >= '0' && a[i] <= '9') { sum = sum + (a[i] - '0') * pow(10, idx); idx++; i--; // 递减i以继续检查前一个字符 }
if (sum != 0) // 如果遇到符号,则将其推入栈中 { s.push(sum); }
// 如果当前字符是运算符,则处理运算符 if (a[i] == '+' || a[i] == '-' || a[i] == '*' || a[i] == '/') { int num1 = s.top(); s.pop(); // 弹出栈顶元素 int num2 = s.top(); s.pop(); // 加、减、乘、除运算: if (a[i] == '+') s.push(num2 + num1); else if (a[i] == '-') s.push(num2 - num1); else if (a[i] == '*') s.push(num2 * num1); else if (a[i] == '/') s.push(num2 / num1); } }
cout << s.top(); return 0;}
转后缀表达式
// 部分逻辑同上#include <iostream>#include <string>#include <stack>#include <cmath>using namespace std;
int main(){ stack <int> s; string a; getline(cin, a);
for (int i = 0; i < a.length() - 1; i++) { // 初始化sum来构建数字 int sum = 0; // 当当前字符是数字时,构建数字 while (a[i] >= '0' && a[i] <= '9') { sum = sum * 10 + (a[i] - '0'); i++; }
if (sum != 0) { push(sum); }
if (a[i] == '+' || a[i] == '-' || a[i] == '*' || a[i] == '/') { int num2 = top(); pop(); int num1 = top(); pop(); if (a[i] == '+') push(num1 + num2); else if (a[i] == '-') push(num1 - num2); else if (a[i] == '*') push(num1 * num2); else if (a[i] == '/') push(num1 / num2); } }
cout << top(); return 0;}
五、结语
部分内容来源于网络,在此声明。
希望这篇文章能帮助你们更好地理解栈。如果你有任何问题,欢迎在评论区留言。
OK,以上就是今天要讲的内容。大家喜欢就点个赞吧,我会尽快更新!ヾ(•ω•`)o!