中缀转后缀——逆波兰表示

来源:互联网 发布:通达信原油看盘软件 编辑:程序博客网 时间:2024/06/06 06:58

       计算机无法识别数学表达式中的括号以及四则运算的先后顺序,因此需要把数学表达示转换成一种计算机能识别的,逆波兰表示就能很好的解决这个问题。逆波兰表示是数学表达式中的一种不需要括号的后缀表达法。即把一个中缀数学表达式改变成一个后缀表示。中缀表示的意思就是运算符在要计算的数字中间,而后缀表示就是运算符在要计算的数字之后。

       例如:9+(3-1)*3+6/2   这就是一个中缀表示,和正常的数学表达式一样

                 931-3*+62/+     这就是一个后缀表示

转换规则:

       1.从左到右遍历中缀表达式的每一个数字和符号,若是数字就输出,即成为后缀表达式的一部分;

       2.若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止;若是左括号或者优先级高于栈顶符号则入栈。

以上面的例子为例说明规则:  (假定同一优先级在栈内的优先级高于栈外优先级)

      1.从左到右依次遍历的第一个字数是9,因为是数字,不入栈,照常输出;

      2.第二个字符是+,因为是符号,同时栈内为空,则入栈;

     3.第三个字符是(,因为是左括号,入栈;

     4.第四个字符是3,因为是数字,不入栈,照常输出;

     5.第五个字符是-,因为其优先级比(低,入栈;

     6.第六个字符是1,因为是数字,不入栈,照常输出;

     7.第七个字符是),因为是右括号,栈中靠近栈顶的第一个左括号之后的所有元素输出,该例中则把栈顶元素-输出,同时栈中的左括号(出栈,但是并不输出,右括号)也不输出;        //此时栈中就剩下字符+

     8.第八个字符是*,因为其优先级高于栈顶元素+,入栈;

     9.第九个字符是3,因为是数字,不入栈,照常输出;  

     10.第十个字符是+,因为其优先级低于栈顶元素*,因此,栈顶元素*输出,此时栈中的栈顶元素变为字符+,因为先进栈的优先级高于后进栈(可理解为同一优先级中栈内的优先级高于栈外的优先级),因此栈顶元素+输出,此时,栈为空,字符+入栈;(当然,假如栈中还存在元素,但是其栈顶元素优先级高于当前遍历字符的优先级,同样把当前遍历的字符入栈,如第5步;反之,继续把栈中元素输出,直到栈顶元素优先基高于当前遍历的字符或者栈为空为止)

     11.12.13各位看官根据我说的自己试着写一下吧。最后结果就在上面哦。

      上面所述是中缀转后缀的具体实施步骤,根据这写出代码还是有一定难度的,当然大神除外,大神的话就不需要看下面了。

      代码的实现的难度在于怎么去很好的区分四则运算符的优先级,以及括号的优先级,还有栈内栈外的优先级。为解决这个麻烦事,作了以下假定:

       栈内      数值                    栈外        数值

        -             4                         -             3

        +            4                        +             3

        *             6                        *              5

        /             6                        /              5

        (             2                       (               10

                                               )              2

解释下:加减的优先级低于乘除的优先级,且栈外的加减的优先级低于栈内的优先级,因此可以假设用数值3代表栈外的加减,栈内的加减的优先级要比栈外高,因此只需要把数值加1即可,即4,同理可得乘除的,括号这比较特殊,左边的括号在栈外时其优先级要最大才行,因为遇到左括号就需要入栈,但是在栈中时为了能让其他的再进来,就必须又要保证它的优先级最小才行,右括号一遍历到就需要把离栈顶最近的左括号上的所有元素都输出,而且括号不要输出,所以可以假定右括号在栈外的数值和栈中左括号值相等,当出现相等的情况时就能明白有一对括号出现。

       说了一堆是不是没看懂啊,没关系,我现在就附上我写的代码,不过我这代码有很大的局限性,不过解决这个中缀转后缀是没什么问题的。(局限性就让各位看官自己猜吧)

这是main.cpp文件

#include"stack.h"int main(){SqStack s;char str[] = "9+(3-1)*3+6/2";init_stack(&s);      //初始化栈mid_lat(&s, str);    //中缀转后缀printf_s("%s\n", str);return 0;}
这是stack.h文件
#pragma once#include<stdio.h>#include<assert.h>#include<stdlib.h>#include<string.h>#define MAXSIZE 30#define ElemType chartypedef struct{ElemType data[MAXSIZE];int top;}SqStack;void init_stack(SqStack *s);    //初始化栈bool my_push(SqStack *s, ElemType value);   //入栈bool my_pop(SqStack *s,ElemType *p);   //出栈bool mid_lat(SqStack *s, char *p);    //中缀转后缀int sign_fig(char *p);                //符号转换成数值
这是stack.cpp文件
#include"stack.h"void init_stack(SqStack *s)    //初始化栈{assert(s);s->top = -1;       //栈为空时,即s->top=-1}bool my_push(SqStack *s, ElemType value)    //入栈{assert(s);if (s->top == MAXSIZE - 1)       //栈满{return false;}s->top++;s->data[s->top] = value;return true;}bool my_pop(SqStack *s,ElemType *p)  //出栈{assert(s);if (s->top == -1)        //栈空{return false;}*p = s->data[s->top];s->top--;return true;}int sign_fig(char *p)          //符号转换成数值{assert(p);switch (*p){case '-':case '+':return 3;break;case '*':case '/':return 5;break;case '(':return 10;break;case ')':return 2;break;}}bool mid_lat(SqStack *s, char *p){assert(s || p);char *q;char temp;char temp_bra;int num_out;int num_in;q = p;while (*p != '\0')      //遍历表达式{
              //遍历表达式,为数字时输出if (*p >= '0'&&*p <= '9' || *p == ' ') //这是程序的不足处,不足的不多写了,害羞脸{*q = *p;      q++;p++;}else{
                      //栈为空时,栈外是符号时直接入栈if (s->data[s->top] == -1){my_push(s, *p);p++;}else{
                                //比较栈内栈外符号的优先级num_out = sign_fig(p);     //栈外符号数值temp = s->data[s->top];if (temp == '('){num_in = 2;//栈内符号数值,栈内为左括号时,数值赋为2}else{num_in = sign_fig(&temp) + 1;//栈内符号数值}
                               //比较数值,确定优先级
                               //栈内数值小于栈外数值时,即栈内栈顶元素的优先级低于栈外优先级
                              //则栈外元素进栈
if (num_in < num_out)  {my_push(s, *p);p++;}
                             //栈内数值大于栈外数值时,则出栈,输出
else if (num_in > num_out){my_pop(s, q);q++;}
                            //相等时,代表出现了一对括号,栈中左括号出栈,但是不输出else{my_pop(s, &temp_bra);p++;}}}}while (s->top != -1)   //遍历完后,清空栈内元素,把还存在栈中的符号输出{my_pop(s, q);q++;}*q = '\0';    //因为是用字符串来表示表达式,最后需要添加‘\0’return true;}




原创粉丝点击