zoukankan      html  css  js  c++  java
  • 中缀表达式求值

    所用知识:C语言,堆栈操作

    算法思想来自慕课浙江大学《数据结构》陈老师,何老师

    笔记:

    1.堆栈:
        1.1 引子    
            一种数据结构,在函数调用,表达式求值等都有广泛的应用
            中缀表达式:a+b*c-d/e:生活中经常使用,但是计算机不好识别
            后缀表达式:abc*+dc/-:生活中不好使用,但计算机容易识别

            例:
            总结:因此需要一种存储方法,能顺序的存储运算数,在需要时倒叙输出。-->堆栈有
            堆栈的特点:后入先出。

        1.2堆栈的操作
        操作集:长度为maxSize的堆栈S ==> stack,堆栈的元素elementType,那么如下的操作
            stack createStack(int maxSize);//生成空堆栈,其最大长度为maxSize
            int isFull(stack s,int maxSize);//判断栈s是否为空
            void push(stack  s,elementType item);//将元素压入堆栈
            int isEmpty(stack s);//判断堆栈是否为空
            elementType pop(stack s);//删除并返回栈顶元素
            
            1.2.1
                用数组来表示堆栈的方法可以参照文件夹下面的同级目录的文件stackArray.c
                同时还有使用一个数组来表示两个堆栈,twoStack.c
            
            1.2.2使用链表来模拟堆栈
                因为链表有两头,但是堆栈的头指针我们会选择链表的头节点,因为便于删除操作,尾节点不方便进行删除操作
                下面是模拟的示意图
                    head(头指针,没有元素的) --> node1(top指针) --> node2(堆栈中的元素) --> node3 --> node4
                代码可以见:stackLinkList.c

            1.2.3 利用堆栈进行表达式求值
                我们平时所见到的表达式都是中缀表达式,但是如果想求表达式的值,先把中缀表达着中文后缀表达式,
                在利用堆栈对后缀表达式进行求值

                中缀表达式转后缀表达式的思路;
                    首先看一个简单的:
                    中缀表达式:2 + 9 / 3 - 5    后缀表达式:2 9 3 / + 5 -

                    通过对比我们发现,中缀表达式和后缀表达式的数字顺序并没有发生改变,只是符号位置发生了改变
                    所以,我们可以构思,使用一个栈来存在运算符,遇到数字就输出,遇到符号就压栈,如果读入的符号比栈顶的符号
                    优先级高,就压栈,否则就弹栈并输出
                    下面是中缀表达式:2 + 9 / 3 - 5压栈和弹栈的具体步骤
                    输出        堆栈内元素
                    2           
                               +
                    9           
                               /(优先级比+高,压栈)
                    3           
                    / +           -(首先弹出/,但是因为同级运行需要按照从左往右的运算,所以+也需要弹栈)
                    5           -
                    -          (元素全部读取完毕以后,-弹栈)

                    所以中缀表达式:2 + 9 / 3 - 5的后缀表达式为 2 9 3 / + 5 -

                    但是如果遇到带有()的表达式怎么办:遇到"("把"("压入栈中,此时栈中的"("运算级别最低,在按照上面的运算符的运算规则来
                    进行压栈和弹栈。直到读取到")",才把"("弹栈,但是对"("和")"不进行输出

                    举个例子:
                    求下面中缀表达式:2 * (9+6/3-5)+4的后缀表达式

                    输出            堆栈内元素(top->bottom)

                    2
                                     *
                                     ( *
                    9                 + ( *
                    6            
                                     / + ( *
                    3                 
                                     - ( *(首先弹出/,但是因为同级运行需要按照从左往右的运算,所以+也需要弹栈,并输出)
                        / +
                    5
                    -                *(遇到")",把栈里依次弹出,直到遇到第一个"(",但是对"("和")"不进行输出)
                    *                +(遇到+,先弹出*,然后输出)
                    4                +
                    +                NULL(没有元素可读,弹出堆栈中最后一个元素)
                    
                    所以中缀表达式:2 * (9+6/3-5)+4的后缀表达式为: 2 9 6 3 / + 5 - * 4 +

    代码实现

    思路:中缀表达式先转后缀表达式在求值

    只支持0-9之间的数字的+-*/以及(),支持括号里面嵌套括号,如3*(2*3-4*1+(3*5)/3)*3+2

    不支持分开的括号3*(2*3-4*1+(3*5)/3)*3+2+(4/2)

    如果有给出修改意见,感激不尽。写的比较匆忙,代码的复用性和注释的完整性可能不是很好

      1 #include<stdio.h>
      2 #include<stdlib.h>
      3 #include<string.h>
      4 #include<math.h>
      5 #include<ctype.h>
      6 #define MAXSIZE 100
      7 
      8 
      9 #include<stdio.h>
     10 #include<stdlib.h>
     11 /*使用链表来模拟堆栈,*/
     12 
     13 
     14 
     15 /*=======================================================定义double类型的堆栈链式存储并进行相关的压栈,弹栈等操作===============================================================*/
     16 
     17 //定义double类型的堆栈的链式存储
     18 typedef struct node3{
     19     double element;
     20     struct node3 *next;
     21 }integerSta,*pIntegerStack;
     22 
     23 //构造一个double类型的链式栈
     24 pIntegerStack createIntegerEmptyStack(){
     25     pIntegerStack stack;
     26     stack = (pIntegerStack)malloc(sizeof(integerSta));
     27     if(stack){
     28         stack->next=NULL;
     29     }
     30     return stack;
     31 }
     32 
     33 //判断double类型的链式栈是否为空
     34 int isIntegerEmpty(pIntegerStack stack){
     35     if(stack->next==NULL){
     36         return 1;
     37     }else{
     38         return 0;
     39     }
     40 }
     41 
     42 //压栈
     43 void pushInteger(pIntegerStack stack,double element){
     44     pIntegerStack node = (pIntegerStack)malloc(sizeof(integerSta));
     45     node->element=element;
     46     node->next=stack->next;
     47     stack->next=node;
     48 }
     49 
     50 //弹栈
     51 double popInteger(pIntegerStack stack){
     52     double element;
     53     pIntegerStack topHead;
     54     if(isEmpty(stack)){
     55         printf("the stack is empty,can not pop");
     56         return;
     57     }else{
     58         topHead = stack->next;
     59         stack->next = topHead->next;
     60         element = topHead->element;
     61         free(topHead);
     62         return element;
     63     }
     64 }
     65 
     66 //取栈顶元素
     67 double getIntegetStackTopElement(pIntegerStack stack){
     68     return (stack->next->element);
     69 }
     70 
     71 //打印栈内元素
     72 void toStringInteger(pIntegerStack stack){
     73     pIntegerStack top = stack->next;
     74     printf("toString:");
     75     while(top!=NULL){
     76         printf("%f ",top->element);
     77         top=top->next;
     78     }
     79     printf("
    ");
     80 }
     81 
     82 
     83 
     84 
     85 /*================================================定义一个存储字符的线性表=========================================================================*/
     86 
     87 
     88 
     89 //构造一个线性表存储后缀表达式
     90 typedef struct node2{
     91     char data[MAXSIZE];
     92     int length;
     93 }li,*pList;
     94 
     95 
     96 
     97 //初始化线性表
     98 pList createEmptyList(){
     99     pList p;
    100     p = (pList)malloc(sizeof(li));
    101     if(p){
    102         p->length=-1;
    103     }
    104     return p;
    105 }
    106 
    107 //向线性表中插入元素
    108 void insert(pList list,char c){
    109     if(list){
    110         list->data[++(list->length)]=c;
    111     }
    112 }
    113 
    114 //将线性表中的元素打印
    115 void toStringList(pList list){
    116     int i;
    117     for(i=0;i<=list->length;i++){
    118         printf("%c ",list->data[i]);
    119     }
    120     printf("
    ");
    121 
    122 }
    123 
    124 
    125 
    126 /*==================================================定义一个字符栈并进行相关操作=================================================================*/
    127 //定义字符栈
    128 typedef struct node{
    129     char element;
    130     struct node *next;
    131 }sta,*pStack;
    132 
    133 //创建一个空的字符链式栈
    134 pStack createEmptyStack(){
    135     pStack stack;
    136     stack = (pStack)malloc(sizeof(sta));
    137     if(stack){
    138         stack->next=NULL;
    139     }
    140     return stack;
    141 }
    142 
    143 //判断链式栈是否为空
    144 int isEmpty(pStack stack){
    145     if(stack->next==NULL){
    146         return 1;
    147     }else{
    148         return 0;
    149     }
    150 }
    151 
    152 //把元素压入栈
    153 void push(pStack stack,char element){
    154     pStack node = (pStack)malloc(sizeof(sta));
    155     node->element=element;
    156     node->next=stack->next;
    157     stack->next=node;
    158 }
    159 
    160 //把元素弹栈
    161 char pop(pStack stack){
    162     char element;
    163     pStack topHead;
    164     if(isEmpty(stack)){
    165         printf("the stack is empty,can not pop");
    166         return NULL;
    167     }else{
    168         topHead = stack->next;
    169         stack->next = topHead->next;
    170         element = topHead->element;
    171         free(topHead);
    172         return element;
    173     }
    174 }
    175 
    176 //获取栈顶元素
    177 char getTopElement(pStack stack){
    178     if(isEmpty(stack)){
    179         printf("the stack is empty,can not get top element");
    180         return;
    181     }else{
    182         return (stack->next->element);
    183     }
    184 }
    185 
    186 
    187 
    188 /*=============================================中缀表达式转后缀表达式=====================================================================*/
    189 
    190 
    191 //打印字符数组
    192 void charArrayToString(char *arr){
    193     char *p  = arr;
    194     while(*p!=''){
    195         printf("%c ",*p);
    196         p = p+1;
    197     }
    198 }
    199 
    200 
    201 
    202 /*
    203 判断字符c是否存在字符数组arr中
    204 存在,返回1
    205 不存在,返回0
    206 */
    207 int isCharArrContainChar(char arr[],char c){
    208     char *p =arr;
    209     while(*p!=''){
    210         if(*p==c){
    211             return 1;
    212         }
    213         p = p+1;
    214     }
    215     return 0;
    216 }
    217 
    218 
    219 /*给定一个运算符,判断他的优先级,返回数字越大,优先级越高,例如
    220     operatorPriorityArr是一个二维数组,下面是模拟的内容,优先级用户可以自定义,数组按元素优先级由低到高排列
    221         0 +-    第0优先级
    222         1 * /   第1优先级
    223         2 ()    第2优先级
    224 
    225     c:等待判断优先级的运算符
    226 */
    227 int getCharIndex(char c,char operatorPriorityArr[][MAXSIZE],int length){
    228     int i;
    229     for(i=0;i<length;i++){
    230         if(isCharArrContainChar(operatorPriorityArr[i],c)){
    231             return i;
    232         }
    233     }
    234     return -1;
    235 }
    236 
    237 
    238 /*
    239 判断字符栈的栈顶元素的优先级和读入字符的优先级
    240 参数:
    241     stackTopEle:栈顶元素
    242     readChar:读入的元素
    243     operatorPriorityArr:用户自定义的运算符优先级二维字符数组,数组按元素优先级由低到高排列
    244     length:二维数组的行数
    245 
    246 比较规则:
    247     1.如果读入的字符为"(",那么"("的优先级最高,直接压栈
    248     2.如果栈顶元素为"(",其优先级最低,eadChar直接入栈
    249     3.如果读入的元素readChar优先级大于栈顶元素,则readChar入栈。例如eadChar为"*" topChar为"+",则"*"入栈
    250     4.如果读入的元素readChar优先级小于或者等于(因为运算需要按照从左往右的顺序)栈顶元素,则topChar弹栈并输出(记录)。
    251         再次判断readChar和当前栈顶元素的优先级,如果当readChar还是优先级小于或者等于当前栈顶元素,接着弹栈并输出(记录)。
    252         一直比较,直到readChar的优先级大于栈顶元素或者栈为空。
    253     5.如果readChar为")",一直弹栈到到第一次遇到"(",并把"("也弹栈,对"("和")"不做输出,其运算符弹栈且输出(记录)
    254 
    255         返回值:
    256             1:压栈
    257             0:读入")" 直到把第一个"("弹栈栈为止
    258             2:弹出当前的栈顶元素,并继续比较
    259 */
    260 int compareOperatorChar(char stackTopEle,char readChar,char operatorPriorityArr[][MAXSIZE],int length){
    261     int index1,index2;
    262     if(stackTopEle=='('){
    263         return 1;//栈为空,直接压栈
    264     }else if(readChar==')'){
    265         return 0;//读入遇到")",直到把第一个"("弹栈栈为止
    266     }else{
    267         //获取两个运算符的优先级
    268         index1 = getCharIndex(stackTopEle,operatorPriorityArr,length);
    269         index2 = getCharIndex(readChar,operatorPriorityArr,length);
    270         if(index1<index2){//比较优先级
    271             return 1;
    272         }else{
    273             return 2;
    274         }
    275     }
    276 }
    277 
    278 
    279 /*
    280 根据优先级的返回结果进行对应的压栈和弹栈操作
    281 参数:
    282     stack:准备好的空字符栈
    283     readChar:读入的字符
    284     operatorPriorityArr:定义的优先级规则
    285     list:储存后缀表达式的字符线性表
    286     length:二维数组的行数
    287 */
    288 void comparePriority(pStack stack,char readChar,char operatorPriorityArr[][MAXSIZE],pList list,int length){
    289     if(isEmpty(stack)){
    290         push(stack,readChar);
    291         return 1;
    292     }else{
    293         char topEle = getTopElement(stack);
    294         int result = compareOperatorChar(topEle,readChar,operatorPriorityArr,length);
    295         if(result==0){
    296             while(getTopElement(stack)!='('){
    297                 insert(list,pop(stack));
    298             }
    299             pop(stack);
    300             return;
    301         }else if(result==1){
    302             push(stack,readChar);
    303             return;
    304         }else{
    305             insert(list,pop(stack));
    306             //递归再次比较
    307             comparePriority(stack,readChar,operatorPriorityArr,list,length);
    308         }
    309     }
    310 }
    311 
    312 
    313 /*
    314 根据中缀表达式或者后缀表达式,转换规则:
    315     1.对于数字,进行原样的输出或者记录
    316     2.对于运算符,根据优先级进行压栈弹栈操作,优先级比较规则参照上面
    317 参数:
    318     stack:准备好的空字符栈
    319     arr:中缀表达式的字符数组,支持空格隔开
    320     operatorPriorityArr:定义的优先级规则
    321     list:储存后缀表达式的字符线性表
    322     length:二维数组的行数
    323 */
    324 char* getBehindExpress(pStack stack,char *arr,char operatorPriorityArr[3][MAXSIZE],pList list,int length){
    325     char *p  = arr;
    326     while(*p!=''){
    327         if(*p>='0' && *p<='9'){
    328             insert(list,*p);
    329         }else if(*p==' '){
    330             p = p+1;
    331             continue;
    332         }else if(getCharIndex(*p,operatorPriorityArr,length)!=-1){//判断运算符是否和法
    333                 comparePriority(stack,*p,operatorPriorityArr,list,length);
    334         }else{
    335             printf("the operational character is illegal
    ");
    336             return "error";
    337         }
    338         p = p+1;
    339     }
    340     //当数字读取完毕后,要把栈里面的运算符全部弹栈
    341     while(!isEmpty(stack)){
    342         insert(list,pop(stack));
    343     }
    344 }
    345 
    346 //打印字符栈里面的元素
    347 void toString(pStack stack){
    348     pStack top = stack->next;
    349     printf("toString:");
    350     while(top!=NULL){
    351         printf("%c ",top->element);
    352         top=top->next;
    353     }
    354     printf("
    ");
    355 }
    356 
    357 
    358 
    359 
    360 /*==================================================计算后缀表达式的值==========================================================================*/
    361 /*计算规则如下:
    362 求后缀表达式的值
    363             6 2 / 3 - 4 2 * + =
    364 
    365             后缀表达式的求解原理:遇到数值先记录(压栈),遇到符号才计算(弹栈两个元素)。计算离符号最近的两个数
    366             1.6 2 / ==> 3 压栈
    367             2.3 3 - ==> 0 压栈
    368             3.0 4 2 * ==> 0 8
    369             4.0 8 + ==>8
    370             5.8 = ==> 8
    371 */
    372 double getValueByAfterExpress(pList list,pStack stack){
    373     int i,store;
    374     double temp,a1,a2;
    375     for(i=0;i<=list->length;i++){
    376         //printf("test");
    377         char c = list->data[i];
    378         if(c>='0' && c<='9'){
    379             store = c-'0';//字符转换为数字
    380             temp = store*1.0;//整形转换为double型
    381             //printf("double:%f
    ",temp);
    382             pushInteger(stack,temp);//数字就压栈
    383         }else{
    384             //弹栈并根据运算符做运算
    385             double a1 = popInteger(stack);
    386             double a2 = popInteger(stack);
    387             if(list->data[i]=='+'){
    388                 temp = a1+a2;
    389                 pushInteger(stack,temp);
    390             }
    391 
    392             if(list->data[i]=='-'){
    393                 temp = a2-a1;
    394                 pushInteger(stack,temp);
    395             }
    396             if(list->data[i]=='*'){
    397                 temp = a1*a2;
    398                 pushInteger(stack,temp);
    399             }
    400             if(list->data[i]=='/'){
    401                 temp = a2/a1;
    402                 pushInteger(stack,temp);
    403             }
    404 
    405         }
    406         //toStringInteger(stack);
    407     }
    408     //最终的栈顶元素即为所求的值
    409     return getIntegetStackTopElement(stack);
    410 }
    411 
    412 
    413 
    414 void main(){
    415     int n = 3,i;
    416     pStack stack  = createEmptyStack();
    417     pStack numberStack   = createIntegerEmptyStack();
    418     pList list = createEmptyList();
    419 
    420     char arr1[] = "2 * ( 9 + 6 / 3 - 5 ) + 4";
    421     char arr2[] = "2 + 9 / 3 - 5";
    422     char arr3[] = "3*(2*3-4*1+(3*5)/3)*3+2";
    423     char operatorPriorityArr[3][MAXSIZE]={"+-","*/","()"};
    424     //计算二维数组的行数
    425     int length=sizeof(operatorPriorityArr)/sizeof(operatorPriorityArr[0]);
    426     //char operatorArr[] = "+-*/()";
    427     getBehindExpress(stack,arr3,operatorPriorityArr,list,length);
    428     //toStringList(list);
    429     double value = getValueByAfterExpress(list,numberStack);
    430     printf("the express %s caculate result is %f",arr3,value);
    431     //double c = (double)('9.23');
    432     //printf("test:%f",c);
    433     //printf("%d",length);
    434 }
    表达式求值
  • 相关阅读:
    Spring源码分析(五)获取Document
    Spring源码分析(四)容器的基础XmlBeanFactory
    Spring源码分析(三)容器核心类
    Spring源码分析(二)容器基本用法
    day23 框架之基础加强
    Java web项目综合练习(Estore)
    第16 天 JavaWEB过滤器和监听器技术
    第17天 笔记 文件上传下载
    Javaweb 第15天 web练习和分页技术
    【剑指offer】数组中的逆序对,C++实现
  • 原文地址:https://www.cnblogs.com/yghjava/p/6629622.html
Copyright © 2011-2022 走看看