C语言中缀表达式转成后缀表达式,并计算它的值

在C语言中,将中缀表达式转成后缀表达式,并计算它的结果,具体的思路如下:
1、定义两个栈,numStack用于存放运算对象,最后存放运算结果的,fuStack用于存放运算符号的
2、从左到右遍历字符串
3、如果当前的字符是一个数字,那么先不要着急将其转成数字,然后压入到numStack中,因为考虑到多位数字的情况,所以需要从当前下标开始遍历,一直遍历到第一个运算符出现,那么这时候才可以将运算符前面的数字转成字符串。然后调用atoi,将字符串转成一个数字。这时候,将这个数字输出,同时将其压入到numStack中。
4、如果当前的字符是一个字符,那么这时候需要分几种情况进行讨论:

(1)如果栈为空或者当前符号是一个左括号,直接将当前符号压入到fuStack中
(2)否则,如果栈顶符号是一个左括号,那么直接将当前符号压入到fuStack中
(3)否则,如果当前符号是一个右括号,那么需要将从fuStack中跳出字符,并输出这
个字符,然后从numStack中跳出两个数字,进行相应的运算,将运算结果压numStack
中,重复(3)操作,直到fuStack的栈顶符号是一个左括号,那么这时候,将左括号从
fuStack中跳出,注意不需要输出
(4)否则,当前符号是一个普通运算符的时候,那么这时候,需要比较当前符号和栈 
  顶符号的优先级,如果当前的符号优先级大于栈顶符号的优先级,那么直接将当前符
号压入到fuStack中,否则,当前符号的优先级小于等于栈顶符号的优先级,那么需要将
栈顶符号跳出,并输出,然后从numStack中跳出两个数字,进行相应的运算,然后将
运算结果压入到numStack中,重复这个步骤,直到当前符号的优先级大于栈顶符号的优
先级才可以将当前符号压入到fuStack中

5、遍历完之后,操作还没有结束,还需要判断fuStack是否为空,如果不为空,那么就从fuStack中跳出栈顶元素,并将其输出,同时,将从numStack中跳出两个数字,进行相应的运算,将运算结果压入到numStack中,重复5的操作,直到fuStack为空。
6、这时候,上述操作都完成之后,这时候numStack的栈顶元素就是整个表达式的运算结果,将其输出即可。

题目的链接:
https://pintia.cn/problem-sets/434/problems/5893
对应的代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_SIZE 21
#define ERROR 0
#define OK 1
typedef struct Num{
    int msg[MAX_SIZE];
    int top;
}numStack;
void initStack(numStack *num){
    num->top = 0;
}

int push(numStack *num,int e){
    if(num->top == MAX_SIZE)
        return ERROR;
    num->msg[num->top++] = e;
    return OK;
}
int pop(numStack *num,int *e){
    if(num->top == 0)
        return ERROR;
    *e = num->msg[--num->top];
    return OK;
}
int getTop(numStack *num,int *e){
    if(num->top == 0)
        return ERROR;
    *e = num->msg[num->top - 1];
    return OK;
}
int isEmpty(numStack *num){
    return num->top == 0;
}
typedef struct FU{
    char msg[MAX_SIZE];
    int top;
}fuStack;
void initFuStack(fuStack *fu){
    fu->top = 0;
}

int pushFu(fuStack *fu,char e){
    if(fu->top == MAX_SIZE)
        return ERROR;
    fu->msg[fu->top++] = e;
    return OK;
}
int popFu(fuStack *fu,char *e){
    if(fu->top == 0)
        return ERROR;
    *e = fu->msg[--fu->top];
    return OK;
}
int getFuTop(fuStack *fu,char *e){
    if(fu->top == 0)
        return ERROR;
    *e = fu->msg[fu->top - 1];
    return OK;
}
int isFuEmpty(fuStack *fu){
    return fu->top == 0;
}
int level(char ch){
    if(ch == '+' || ch == '-')
        return 1;
    else if(ch == '*' || ch == '/')
        return 2;
    else
        return 0;
}
int isNum(char ch){
    if(ch >= '0' && ch <= '9')
        return 1;
    return 0;
}
int yunsuan(char ch,numStack *num,int *result){
   int a,b;
   pop(num,&a);
   pop(num,&b);//将从栈中跳出两个元素,并将他们的值赋给a、b
   /*
   值得注意的是,必须是b - a,b / a,因为栈式先进后出的结构
   */
   switch(ch){
      case '+':
          *result = b + a;
           break;
      case '-':
          *result = b - a;
           break;
      case '*':
          *result = b * a;
           break;
      case '/':
          if(a == 0){
            return ERROR;//如果不符合运算法则,那么返回ERROR
          }
          *result = b / a;
          break;
   }
   return OK;
}
void getPreExpression(numStack *num,fuStack *fu,char *msg){
    int i,result,j,k = 0,a,b,count = 0;//count表示数字的个数
    char ch,tmp,arr[MAX_SIZE];//arr数组用于多位数字的拼接,ch表示当前的字符,tmp表示fuStack的栈顶元素
    for(i = 0; msg[i] != '\0'; i++){
        ch = msg[i];
        if(isNum(ch)){
            j = i;
            k = 0;//重置k
            //拼接数字
            while(isNum(msg[j])){
                arr[k++] = msg[j];
                j++;
            }
            arr[k] = '\0';//这一步十分重要
            /*
            这一步将i回到最后一个数字,因为在for循环中还会进行i++的操作,
            如果没有这一步,那么就会导致读取到的字符不全
            */
            i = j - 1;
            a = atoi(arr);//调用atoi方法,从而将这个多位数字的字符串转成整形数字
            count++;
            if(count == 1)
                printf("%d",a);//如果是第一个数字,那么前面不需要输出一个空格,否则要在前面输出空格
            else
                printf(" %d",a);
            push(num,a);//将数字压入栈中
        }else{
            //如果是运算符,那么需要分情况讨论
            if(isFuEmpty(fu) || ch == '('){
                //如果栈为空或者当前字符为左括号,直接将当前符号压入栈中
                pushFu(fu,ch);
            }else{
                /*
                如果栈不为空,那么需要讨论几种情况:
                ①栈顶是左括号,直接将当前字符压入栈中
                ②否则,如果当前符号是一个右括号,那么将从栈中跳出栈顶元
                素,并将其输出,同时将从numStack栈中跳出两个数字,进行相应
                的运算,之后将运算结果压入到numStack中,重复③的操作,直到
                栈顶符号式左括号,之后将左括号从fuStack中跳出
                ③否则,当前字符是普通字符,那么需要判断优先级。如果当前符
                号的优先级大于栈顶元素的优先级,那么直接入fu栈,否则从符栈
                中不断跳出栈顶元素,并将其输出,同时将从numStack中跳出两
                个数字,进行相应的运算,然后将运算结果压入到numStack中,
                重复此操作,直到当前符号的优先级大于栈顶符号的优先级,才将
                当前符号压入到fuStack中
                */
                getFuTop(fu,&tmp);
                if(tmp == '('){
                    //如果栈顶元素是一个左括号,那么直接入栈
                    pushFu(fu,ch);
                }else{
                  //当前的字符不是一个左括号,那么需要判断当前的符号是否为一个右括号
                  if(ch == ')'){
                    getFuTop(fu,&tmp);
                    while(tmp != '('){
                       popFu(fu,&tmp);
                       printf(" %c",tmp);
                       if(!yunsuan(tmp,num,&result)){
                          printf("被除数不可以为0,运算错误!!!\n");
                          return;
                       }
                       push(num,result);//如果运算符合运算法则,那么将运算结果压入到栈中
                       getFuTop(fu,&tmp);
                    }
                    popFu(fu,&tmp);
                  }else{
                     //当前的符号是一个普通符号,那么需要比较优先级
                     label:
                         if(isFuEmpty(fu) || level(ch) > level(tmp)){
                                //当前符号的优先级大于栈顶符号的优先级,那么直接入栈
                            pushFu(fu,ch);
                         }else{
                             //当前的符号的优先级小于等于栈顶符号的优先级,那么将栈顶元素从fu栈中跳出并输出
                            popFu(fu,&tmp);
                            printf(" %c",tmp); 
                            if(!yunsuan(tmp,num,&result)){
                                printf("被除数不可以为0,运算错误!!!\n");
                                return;
                            }
                            push(num,result);//如果运算符合运算法则,那么将运算结果压入到栈中
                            getFuTop(fu,&tmp);
                            goto label;//利用goto语句,从而实现当前的符号的优先级小于栈顶符号的优先级,然后将其压入
                         }
                  }
                }
            }

        }
    }
    //将num压入到fu栈中
    while(!isFuEmpty(fu)){
         popFu(fu,&tmp);
         printf(" %c",tmp);
         if(!yunsuan(tmp,num,&result)){
         //将进行相应的运算,然后将对应的运算结果赋值给result
            printf("被除数不可以为0,运算错误!!!\n");
            return;
         }
         push(num,result);//如果运算符合运算法则,那么将运算结果压入到栈中
    }
    printf("\n");
    pop(num,&a);//将num中的栈顶元素的值赋给a,并将其删除
    printf("%s的运算结果为%d\n",msg,a);
}
int main(){
    numStack *num = (numStack *)malloc(sizeof(numStack));
    fuStack *fu= (fuStack *)malloc(sizeof(fuStack));
    char msg[MAX_SIZE];
    initStack(num);//将栈进行初始化
    initFuStack(fu);
    scanf("%s",msg);//输入字符串
    getPreExpression(num,fu,msg);//将后缀表达式输出,同时将它的运算结果输出
    return 0;
}


对应的结果:
在这里插入图片描述
在这里插入图片描述

不足之处:
1、如果数字是一个小数的情况,则时候就会明显发生错误。
如下图,输入这样的例子,就直接程序结束了.
在这里插入图片描述
2、如果一开始输入的就是负数之类的数的话,那么这时候也是不可以进行运算的。比如-5+6等诸如这样的例子,不可以进行运算。

如果有什么好的建议,请大家指正哈!

C语言中,我们可以使用顺序栈结构来实现中缀表达式转后缀表达式的操作。这可以通过遍历中缀表达式的每个字符,并按照一定的规则将其转换为后缀表达式来完成。 中缀表达式转后缀表达式的原因是为了更方便地进行计算和处理。逆波兰式(也叫后缀表达式)将运算符写在操作数之后,避免了括号的使用和运算符的优先级问题,使得表达式的计算更加直观和简单。 在转换中缀表达式后缀表达式的过程中,我们可以使用堆栈来辅助实现。按照以下规则进行操作: 1. 遍历中缀表达式的每个字符。 2. 若遇到操作数,直接输出到后缀表达式中。 3. 若遇到运算符,判断运算符的优先级: - 若堆栈为空,或者堆栈顶部元素为左括号'(',直接将运算符入栈。 - 若堆栈顶部元素的优先级小于当前运算符,将当前运算符入栈。 - 若堆栈顶部元素的优先级大于或等于当前运算符,将堆栈顶部的运算符依次弹出并输出到后缀表达式中,直到堆栈为空或者遇到左括号'('为止,然后将当前运算符入栈。 4. 若遇到左括号'(',直接入栈。 5. 若遇到右括号')',将堆栈顶部的运算符依次弹出并输出到后缀表达式中,直到遇到左括号'(',然后将左括号弹出但不输出。 6. 遍历结束后,将堆栈中剩余的运算符依次弹出并输出到后缀表达式中。 通过以上规则,我们可以将中缀表达式转换为后缀表达式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [c语言实现中缀表达式转后缀并求值](https://download.csdn.net/download/kongchengyeyu/10336788)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [C语言中缀表达式转后缀表达式](https://blog.csdn.net/m0_55124878/article/details/120423212)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [C语言实现中缀表达式后缀表达式的转换](https://blog.csdn.net/DarkSide_/article/details/104182084)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值