• 中缀表达式转后缀表达式详细思路及代码实现


    什么是中缀表达式?

    中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(eg:3+43+4*28+(17-6*2)….)。

    为什么要中缀表达式转后缀表达式?

    但是中缀表达式不易被计算机处理。我们在计算一个式子(通常为中缀表达式)时,需要将中缀表达式转化为后缀表达式。

     什么是后缀表达式?

    那么后缀表达式,又称逆波兰式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)。一般用栈来模拟。

    怎么把中缀表达式转成后缀表达式呢?

    举一个简单的栗子:

    (3+4)×5-2

    画成树大概是这样的:

    所以后缀表达式为:

    3  4  +  5  ×  2  -

    以下是转换的思路:

    1.初始化两个字符型数组模拟栈:字符存入栈s1和储存中间结果的栈s2

    2.从左至右扫描中缀表达式;

    3.遇到操作数时,将其压s2

    4.遇到运算符时,比较其与s1栈顶运算符的优先级:

    如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;

    否则,若优先级比栈顶运算符的高,也将运算符压入s1

    否则,将s1栈顶的运算符弹出并压入到s2中,再次转到s1中新的栈顶运算符相比较;

    5.遇到括号时:

    如果是左括号“(”,则直接压入s1

    如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;

    6.重复步骤25,直到表达式的最右边;

    7.将s1中剩余的运算符依次弹出并压入s2

    8.依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

    然后就可以按照后缀表达式来计算了。

    一定要注意取出元素的计算顺序!先取出的数为X(X为减///),后取出的数为X

     代码(有详细注释):

    1. #include<bits/stdc++.h>//万能头文件
    2. using namespace std;
    3. #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//加速语句
    4. typedef long long ll;
    5. const int N=1e5+10;
    6. char s1[N],s2[N],s[N];
    7. ll top1,top2,p,js[N],topis;
    8. int lev(char n)
    9. {
    10. if(n=='+'||n=='-') return 1;
    11. if(n=='*'||n=='/') return 2;
    12. if(n=='^') return 3;
    13. return 0;
    14. }
    15. void print()
    16. {
    17. for(int i=1;i<=topis;i++)//当前正在算的
    18. {
    19. cout<<js[i]<<' ';
    20. }
    21. for(int i=p+1;i<=top2;i++)//后面还没有遍历到的
    22. {
    23. cout<<s2[i];
    24. if(i!=top2)
    25. cout<<" ";
    26. }
    27. if(p!=top2)
    28. cout<<endl;
    29. }
    30. int main()
    31. {
    32. cin>>s;
    33. for(int i=0;i<strlen(s);i++)
    34. {
    35. if(s[i]<='9'&&s[i]>='0')
    36. {
    37. s2[++top2]=s[i];
    38. }
    39. else
    40. {
    41. if(s[i]=='(')
    42. {
    43. s1[++top1]=s[i];
    44. continue;
    45. }
    46. if(s1[top1]=='('||top1==0)
    47. {
    48. s1[++top1]=s[i];
    49. continue;
    50. }
    51. if(lev(s1[top1])>=lev(s[i])&&s[i]!=')')//当进来的不是右括号,且进来的符号优先级没有s1的栈顶符号优先级高
    52. //这个时候需要将s1的栈顶元素给到s2中
    53. {
    54. s2[++top2]=s1[top1--];
    55. while(lev(s1[top1])>=lev(s[i]))//若优先级任然没有要进来的符号优先级高,持续的给到s2中
    56. {
    57. s2[++top2]=s1[top1--];
    58. }
    59. //循环结束后,要进来的符号优先级没有s1的栈顶符号优先级高,则可以存入s1中
    60. s1[++top1]=s[i];
    61. continue;
    62. }
    63. if(lev(s1[top1])<lev(s[i])&&s[i]!=')')
    64. {
    65. s1[++top1]=s[i];
    66. }
    67. if(s[i]==')')//遇到了 ' ) '
    68. {
    69. while(s1[top1]!='(')//将s1中的符号依次给到s2中,直到遇到 ' ) '
    70. {
    71. s2[++top2]=s1[top1--];
    72. }
    73. top1--;
    74. continue;
    75. }
    76. }
    77. }
    78. while(top1>0)//若s1还有符号的话,需要给到s2中
    79. {
    80. s2[++top2]=s1[top1--];
    81. }
    82. for(int i=1;i<=top2;i++)
    83. {
    84. cout<<s2[i]<<" ";
    85. }
    86. cout<<endl;
    87. //完美完成中缀转后缀
    88. //接下来依次计算
    89. for(int i=1;i<=top2;i++)
    90. {
    91. p=i;
    92. if(s2[i]>='0'&&s2[i]<='9')
    93. {
    94. js[++topis]=s2[i]-'0';
    95. }
    96. else //为符号,对栈顶两个元素进行运算,并将结果存入栈顶
    97. {
    98. //注意先进栈的做运算的第一位数
    99. if(s2[i]=='+')
    100. {
    101. ll x=js[topis];
    102. ll y=js[--topis];
    103. ll ans=y+x;
    104. js[topis]=ans;
    105. }
    106. if(s2[i]=='-')
    107. {
    108. ll x=js[topis];
    109. ll y=js[--topis];
    110. ll ans=y-x;
    111. js[topis]=ans;
    112. }
    113. if(s2[i]=='*')
    114. {
    115. ll x=js[topis];
    116. ll y=js[--topis];
    117. ll ans=y*x;
    118. js[topis]=ans;
    119. }
    120. if(s2[i]=='/')
    121. {
    122. ll x=js[topis];
    123. ll y=js[--topis];
    124. ll ans=y/x;
    125. js[topis]=ans;
    126. }
    127. if(s2[i]=='^')
    128. {
    129. ll x=js[topis];
    130. ll y=js[--topis];
    131. ll ans=pow(y,x);
    132. js[topis]=ans;
    133. }
    134. print();//每一步都要打印
    135. }
    136. }
    137. return 0;
    138. }

    运行结果如下:

     

  • 相关阅读:
    小赢科技,寻找金融科技核心价
    奇葩需求记录 各个系统取数据联表展示
    C++查漏补缺与新标准(C++20,C++17,C++11)02 C++快速回顾(二)
    C# 托盘通知
    IP 协议的相关特性
    DAO 的发展状态
    《痞子衡嵌入式半月刊》 第 54 期
    【Android知识笔记】UI体系(三)
    jdk11新特性——局部变量类型推断(var ”关键字”)
    《Effective C++》阅读总结(三):资源管理
  • 原文地址:https://blog.csdn.net/WSY444/article/details/125620416