(C语言)用栈将中缀表达式转为逆波兰(后缀)表达式并计算结果

源代码

#include <stdio.h>
#include <stdlib.h>

typedef struct StackList{
    char ope; //储存操作符的链栈节点
    struct StackList* next;
}Stack;

typedef struct Linklist{
    char ch;//储存操作符和操作数的链表节点
    struct Linklist* next;
}List;

栈的相关操作

Stack* InitStack(){//初始化链栈
    return NULL;
}

Stack* PushStack(Stack** S,char c){//将操作符进栈
    Stack *p=(Stack*)malloc(sizeof(Stack));
    if(!p){
        printf("申请空间失败");
        return NULL;
    }
    p->ope=c;
    if(!*S){
        *S=p;
        (*S)->next=NULL;
    }
    else{
        p->next=*S;
        *S=p;
    }
    return *S;
}

char PopStack(Stack** S){//将栈顶操作符出栈
    char c;
    if(!*S){
        printf("链栈为空");
        return 0;
    }
    Stack *p=*S;
    c=p->ope;
    (*S)=(*S)->next;
    free(p);
    return c;
}

char GetStackTop(Stack* S){//取栈顶操作符
    if(!S){
        printf("链栈为空");
        return -1;
    }
    return S->ope;
}

链表的相关操作

Stack* InitStack(){//初始化链栈
    return NULL;
}

Stack* PushStack(Stack** S,char c){//将操作符进栈
    Stack *p=(Stack*)malloc(sizeof(Stack));
    if(!p){
        printf("申请空间失败");
        return NULL;
    }
    p->ope=c;
    if(!*S){
        *S=p;
        (*S)->next=NULL;
    }
    else{
        p->next=*S;
        *S=p;
    }
    return *S;
}

char PopStack(Stack** S){//将栈顶操作符出栈
    char c;
    if(!*S){
        printf("链栈为空");
        return 0;
    }
    Stack *p=*S;
    c=p->ope;
    (*S)=(*S)->next;
    free(p);
    return c;
}

char GetStackTop(Stack* S){//取栈顶操作符
    if(!S){
        printf("链栈为空");
        return -1;
    }
    return S->ope;
}

判断是否为操作符

int isOperator(char c){//判断是否为操作符
    const char *p="+-*/()";
    while(*p){
        if(c==*p)
            return 1;
        p++;
    }
    return 0;
}

判断操作符优先级

int isPrior(char c1,char c2){//判断操作符优先级
    const char *ch="#+-*/";
    int i=0,j=0;
    while (ch[i]&&ch[i]!=c1)
        i++;
    if(i==2)//加减同级
        i--;
    if(i==4)//乘除同级
        i--;
    while (ch[j]&&ch[j]!=c2)
        j++;
    if(j==2)//加减同级
        j--;
    if(j==4)//乘除同级
        j--;
    if(i>=j)
        return 1;
    else
        return 0;
}

将中缀表达式转为逆波兰(后缀)表达式

List* InversePoland(char* st){//将中缀表达式转为逆波兰(后缀)表达式
    int i=0,j=0;
    char e;
    Stack *Operate=InitStack();//Operate是在转化中储存操作符的链栈指针
    List *Convert=InitList(),*p=NULL;//Convert是储存转化后的逆波兰表达式的链栈指针
    Operate=PushStack(&Operate,st[i]);
    i++;
    while (st[i]!='#'){
        if(!isOperator(st[i])){
            Convert=PushList(Convert,st[i]);//将操作数插入链表
            i++;
        }
        else{
            if(st[i]=='('){
                Operate=PushStack(&Operate,st[i]);//将左括号进栈
                i++;
            }
            else if(st[i]==')'){
                while(GetStackTop(Operate)!='('){
                    if(GetStackTop(Operate)!='#')
                        Convert=PushList(Convert,PopStack(&Operate));//将栈中操作符插入链表
                    else{
                        printf("括号不匹配\n");
                        break;
                    }
                }
                char ch=PopStack(&Operate);
                i++;
            }
            else{
                if(GetStackTop(Operate)!='('&&GetStackTop(Operate)!='#'&&isPrior(GetStackTop(Operate),st[i]))//若当前操作符优先级不高于栈顶操作符优先级,则将栈顶操作符出栈并插入链表
                    Convert=PushList(Convert,PopStack(&Operate));
                else {
                    Operate=PushStack(&Operate,st[i]);
                    i++;
                }
            }  
        }
    }
    while (Operate->ope!='#')
        PushList(Convert,PopStack(&Operate));//将栈中剩余操作符插入链表
    p=Convert;
    while (p){
        printf("%c",p->ch);
        p=p->next;
    }
    printf("\n");
    return Convert;
}

计算两个操作数运算后的值

char Calculate(char c1,char op,char c2){//计算两个操作数运算后的值
    int x1,x2,x;
    char ch[2],c[3];
    ch[0]=c1;
    x1=atoi(ch);//将字符转为整型
    ch[0]=c2;
    x2=atoi(ch);
    switch (op){
        case '+':
            x=x1+x2;
            break;
        case '-':
            x=x1-x2;
            break;
        case '*':
            x=x1*x2;
            break;
        case '/':
            x=x1/x2;
            break;
        default:
            break;
    }
    itoa(x,c,10);//将整型转为字符
    return c[0];
}

计算逆波兰表达式的值

char Calculate_InversePoland(List* Convert){//计算逆波兰表达式的值
    Stack* Opnd=InitStack();
    int i;
    char c,e1,e2,res;
    List* L=Convert;
    while (L){
        if(!isOperator(L->ch))
            PushStack(&Opnd,L->ch);//将操作数进栈
        else{
            e1=PopStack(&Opnd);
            e2=PopStack(&Opnd);
            res=Calculate(e1,L->ch,e2);
            PushStack(&Opnd,res);
        }
        L=L->next;
    }
    return res;
}

主函数

int main(){
    char st[20];
    printf("请输入四则运算式子,且首尾需加上'#'(如#(1+2)*3#)");
    scanf("%s",st);
    List* Convert=InversePoland(st);
    char res=Calculate_InversePoland(Convert);
    printf("%c",res);
}

缺陷

本程序的缺陷在于,当输入的操作数中有多位数时,无法正确计算,因为在将中缀表达式转为逆波兰表达式时,将单个数字转为字符型,没有考虑多位数的情况,或许可以用空格标记一个数字的结束,但笔者尚未尝试。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里澄江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值