• 中缀表达式转后缀表达式并计算——栈


    发现以前给的链接搞错了,尴尬


    X = (56 - 20)*(4 - 3)/(4+2)   ;

    那么计算机该怎么算呢?我们给出的方案是先转化为中缀表达式(参考学过的离散),也就是X = 56#20#-4#3#-*4#2#+/  (用#表示一个数据的结束,便于记录)

    那接下来怎么办呢?对于后缀表达式的处理我们可以利用栈来进行,把数据放入栈中,每当遇到一个运算符时,便出栈并处理一组数据,同时把这组数据的结果再次存入栈中,直到表达式处理结束,我么也就可以得到最后的结果。

    // 我为什么要说也,我好像不记得了。。。。。。

    那么问题来了,如何由中缀表达式转换为后缀表达式?

    先上代码(PS:书上也有解法与本解法不同(本质一样),可自行参考)

     1 template <class ElemType>
     2 void Trans(char * exp, int n, char * postexp) {    // 中缀转后缀
     3     char e;
     4     SqStack <char> * Optr;            // 定义运算符栈指针 
     5     InitStack(Optr, n);        // 初始化运算符栈 
     6     int i = 0;  
     7     while (*exp != '') {
     8         switch (*exp) {
     9         case '(':Push(Optr, '(');        // 左括号进栈 
    10             exp++;
    11             break;
    12         case ')':Pop(Optr, e);            // 右括号元素出栈
    13             while (e != '(') {
    14                 postexp[i++] = e;
    15                 Pop(Optr, e);
    16             }
    17             exp++;
    18             break;
    19         case '+':
    20         case '-':
    21             while (StackEmpty(Optr)) {    // + || -栈不空循环 
    22                 GetTop(Optr, e);        // 取栈顶元素 
    23                 if (e != '(') {
    24                     postexp[i++] = e;    // 将e存放到postexp中 
    25                     Pop(Optr, e);
    26                 }
    27                 else
    28                     break;                // 是 '(' 退出循环 
    29             }
    30             Push(Optr, *exp);            // + || -进栈 
    31             exp++;
    32             break;
    33         case '*':
    34         case '/':
    35             while (StackEmpty(Optr)) {    // * || /栈不空循环 
    36                 GetTop(Optr, e);
    37                 if (e == '*' || e == '/') {
    38                     postexp[i++] = e;
    39                     Pop(Optr, e);
    40                 }
    41                 else
    42                     break;
    43             }
    44             Push(Optr, *exp); 
    45             exp++;
    46             break;
    47         default:            // 数字字符处理 
    48             while (*exp >= '0' && *exp <= '9') {
    49                 postexp[i++] = *exp;
    50                 exp++;
    51             }
    52             postexp[i++] = '#';        // 标识一个数字串结束 
    53         }
    54     }
    55     while (StackEmpty(Optr)) {        // exp扫描完毕
    56         Pop(Optr, e);
    57         postexp[i++] = e;
    58     }
    59     postexp[i] = '';        // 添加结束标识 
    60     DestroyStack(Optr);        // 销毁栈 
    61 }

    简单来说,就是利用运算符的优先级来解决这些问题,对于中缀表达式转化为后缀表达式,我们对运算符的处理是放入一个栈中,当 当前运算符优先级大于栈顶元素优先级时,进栈,反之,不断退栈直到大于栈顶元素优先级为止;对于’(‘我们可以理解为进栈前优先级最高,进栈后优先级最低;

    那么为什么要用模板写呢?

    接下来我们计算后缀表达式:

     1 template <class ElemType>
     2 double Compvalue(char *postexp, int n) {        // 后缀表达式计算
     3     double a, b, rsh, e;
     4     SqStack <double> * Opnd;        // 操作数栈 
     5     InitStack(Opnd, n);
     6     while (*postexp != '') {
     7         switch (*postexp) {
     8         case '+':Pop(Opnd, a);
     9             Pop(Opnd, b);        // + ->出栈两个元素
    10             Push(Opnd, a + b);
    11             break;                // 元素进栈 
    12         case '-':Pop(Opnd, a);
    13             Pop(Opnd, b);
    14             Push(Opnd, b - a);
    15             break;
    16         case '*':Pop(Opnd, a);
    17             Pop(Opnd, b);
    18             Push(Opnd, a*b);
    19             break;
    20         case '/':Pop(Opnd, a);
    21             Pop(Opnd, b);
    22             if (a != 0) {
    23                 Push(Opnd, b / a);
    24                 break;
    25             }
    26             else {
    27                 cout << "除零错误!" << endl;
    28                 exit(0);
    29             }
    30             break;
    31         default:            // 数字字符处理
    32             rsh = 0;
    33             while (*postexp >= '0' && *postexp <= '9') {
    34                 rsh = 10 * rsh + *postexp - '0';
    35                 postexp++;
    36             }
    37             Push(Opnd, rsh);    // 进栈 
    38             break;
    39         }    
    40         postexp++;    
    41     }
    42     GetTop(Opnd, e);
    43     DestroyStack(Opnd);
    44     return e;
    45 }

    需要把字符型数字转化为int、double等类型,接下来,按照顺序一个一个处理就可以了;(但是觉得还是有很多代码类似,应该是可以把它合并简化的)

    好了,那为什么用模板我们也就知道了,因为我们用了两个栈,一个是char栈,一个是double栈,如果定义两个,那完全是重复了很多代码,所以用模板会好一点,但是还有一个问题,在调用Trans函数和Compvalue函数时,如何实例化呢?显然这也是一个问题。

    函数实例化:https://blog.csdn.net/songchuwang1868/article/details/83024484 (无参函数的实例化)

     // 我也不太记得当初是怎么回事了,这个实例化好像也没什么区别,当初是不太明白。

     // 记起来了,以前写的是有参的实例化,直接带入相应类型参数即可,所以无参查了一下,才明白是怎么回事。

    加上一个比较详细的实例化博客:CTHON

    大家还可以考虑一下表达式的输入问题;

    差不多了,附上完整代码

      1 #include<iostream>
      2 #include<cstdlib>
      3 #include<string>
      4 
      5 using namespace std;
      6 
      7 template <class ElemType>
      8 struct SqStack {        //
      9     ElemType *data;
     10     int top;            // 栈顶
     11 };
     12 
     13 template <class ElemType>
     14 void InitStack(SqStack <ElemType> *& s,int length) {    // 初始化
     15     s = (SqStack <ElemType> *)malloc(sizeof(SqStack <ElemType>));
     16     s->data = new ElemType[length];
     17     s->top = -1;
     18 }
     19 
     20 template <class ElemType>
     21 void DestroyStack(SqStack <ElemType> *& s) {        // 销毁
     22     delete[] s->data;
     23     free(s);
     24 }
     25 
     26 template <class ElemType>
     27 bool StackEmpty(SqStack <ElemType> * s) {        // 空 = 0
     28     return (s->top != -1);            // 非空 = 1
     29 }
     30 
     31 template <class ElemType>
     32 void Push(SqStack <ElemType> *& s, ElemType e) {    // 进栈
     33     s->top++;
     34     s->data[s->top] = e;
     35 }
     36 
     37 template <class ElemType>
     38 bool Pop(SqStack <ElemType> *& s, ElemType & e) {     // 出栈
     39     if (s->top == -1)
     40         return false;
     41     e = s->data[s->top];
     42     s->top--;
     43     return true;
     44 }
     45 
     46 template <class ElemType>
     47 bool GetTop(SqStack <ElemType> *& s, ElemType & e) {    // 取栈顶元素
     48     if (s->top == -1)
     49         return false;
     50     e = s->data[s->top];
     51     return true;
     52 }
     53 
     54 template <class ElemType>
     55 void Trans(char * exp, int n, char * postexp) {    // 中缀转后缀
     56     char e;
     57     SqStack <char> * Optr;            // 定义运算符栈指针 
     58     InitStack(Optr, n);        // 初始化运算符栈 
     59     int i = 0;  
     60     while (*exp != '') {
     61         switch (*exp) {
     62         case '(':Push(Optr, '(');        // 左括号进栈 
     63             exp++;
     64             break;
     65         case ')':Pop(Optr, e);            // 右括号元素出栈
     66             while (e != '(') {
     67                 postexp[i++] = e;
     68                 Pop(Optr, e);
     69             }
     70             exp++;
     71             break;
     72         case '+':
     73         case '-':
     74             while (StackEmpty(Optr)) {    // + || -栈不空循环 
     75                 GetTop(Optr, e);        // 取栈顶元素 
     76                 if (e != '(') {
     77                     postexp[i++] = e;    // 将e存放到postexp中 
     78                     Pop(Optr, e);
     79                 }
     80                 else
     81                     break;                // 是 '(' 退出循环 
     82             }
     83             Push(Optr, *exp);            // + || -进栈 
     84             exp++;
     85             break;
     86         case '*':
     87         case '/':
     88             while (StackEmpty(Optr)) {    // * || /栈不空循环 
     89                 GetTop(Optr, e);
     90                 if (e == '*' || e == '/') {
     91                     postexp[i++] = e;
     92                     Pop(Optr, e);
     93                 }
     94                 else
     95                     break;
     96             }
     97             Push(Optr, *exp); 
     98             exp++;
     99             break;
    100         default:            // 数字字符处理 
    101             while (*exp >= '0' && *exp <= '9') {
    102                 postexp[i++] = *exp;
    103                 exp++;
    104             }
    105             postexp[i++] = '#';        // 标识一个数字串结束 
    106         }
    107     }
    108     while (StackEmpty(Optr)) {        // exp扫描完毕
    109         Pop(Optr, e);
    110         postexp[i++] = e;
    111     }
    112     postexp[i] = '';        // 添加结束标识 
    113     DestroyStack(Optr);        // 销毁栈 
    114 }
    115 
    116 template <class ElemType>
    117 double Compvalue(char *postexp, int n) {        // 后缀表达式计算
    118     double a, b, rsh, e;
    119     SqStack <double> * Opnd;        // 操作数栈 
    120     InitStack(Opnd, n);
    121     while (*postexp != '') {
    122         switch (*postexp) {
    123         case '+':Pop(Opnd, a);
    124             Pop(Opnd, b);        // + ->出栈两个元素
    125             Push(Opnd, a + b);
    126             break;                // 元素进栈 
    127         case '-':Pop(Opnd, a);
    128             Pop(Opnd, b);
    129             Push(Opnd, b - a);
    130             break;
    131         case '*':Pop(Opnd, a);
    132             Pop(Opnd, b);
    133             Push(Opnd, a*b);
    134             break;
    135         case '/':Pop(Opnd, a);
    136             Pop(Opnd, b);
    137             if (a != 0) {
    138                 Push(Opnd, b / a);
    139                 break;
    140             }
    141             else {
    142                 cout << "除零错误!" << endl;
    143                 exit(0);
    144             }
    145             break;
    146         default:            // 数字字符处理
    147             rsh = 0;
    148             while (*postexp >= '0' && *postexp <= '9') {
    149                 rsh = 10 * rsh + *postexp - '0';
    150                 postexp++;
    151             }
    152             Push(Opnd, rsh);    // 进栈 
    153             break;
    154         }    
    155         postexp++;    
    156     }
    157     GetTop(Opnd, e);
    158     DestroyStack(Opnd);
    159     return e;
    160 }
    161 
    162 int main()
    163 {
    164     double temp;
    165     string str;
    166     cin >> str;
    167     char *exp = (char *)str.c_str();
    168     char *postexp = new char [str.length()];
    169     cout << "中缀表达式为:" << exp << endl;
    170     Trans<char>(exp,str.length(),postexp);
    171     cout << "转换为后缀表达式为:" << postexp << endl;
    172     temp = Compvalue<double>(postexp, str.length());
    173     cout << "计算表达式的值为:" << temp << endl;
    174     return 0;
    175 }
    View Code

    2020-05-25

  • 相关阅读:
    函数
    A × B problem
    求n的阶乘
    自己构建一个vector函数
    int与string的互相转化
    列一列(斐波那契数列)
    找一找
    c++大数计算模板
    JSON--js中 json字符串转对象、对象转字符串
    JSON
  • 原文地址:https://www.cnblogs.com/2015-16/p/12958259.html
Copyright © 2020-2023  润新知