【数据结构】逆波兰表达式

本文介绍了如何使用逆波兰表达式(后缀表达式)来计算中缀表达式的值。首先,通过栈结构将中缀表达式转换为后缀表达式,然后遍历后缀表达式计算其值。代码实现了处理数字、运算符和括号的功能,但不支持大括号和中括号,且限制为处理整数和两位数的表达式。
摘要由CSDN通过智能技术生成

⭐️写在前面的话⭐️

📒博客主页: 程序员好冰
🎉欢迎 【点赞👍 关注🔎 收藏⭐️ 留言📝】
📌本文由 程序员好冰 原创,CSDN 首发!
📆入站时间: 🌴2022 年 07 月 13 日🌴
✉️ 是非不入松风耳,花落花开只读书。
💭推荐书籍:📚《Java编程思想》,📚《Java 核心技术卷》
💬参考在线编程网站:🌐牛客网🌐力扣
🍭 作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!🍭


逆波兰表达式

代码只实现了小括号的匹配,大括号和中括号的匹配没有实现;

只能够实现整数类型的表达式运算;

只限处理两位数的表达式,两位数以上的没有实现。

0、构建基本的栈结构

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

#define OK 1
#define ERROR 0

#define MAX_SIZE 100

typedef char ElemType;
typedef int Status;

typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode;

typedef struct LinkStack
{
    int count;
    struct LNode *top;
}LinkStack;

Status InitStack(LinkStack* L)
{
    L->top=(LNode*)malloc(sizeof(LNode));
    if(!L->top){
        return ERROR;
    }
    L->top=NULL;
    L->count=0;
    return OK;
}

Status StackIsEmpty(LinkStack L)
{
    if(L.count==0){
        return OK;
    }
    if(L.count!=0){
        return ERROR;
    }
    return OK;
}

ElemType GetTop(LinkStack L)
{
    if(StackIsEmpty(L)){
        return ERROR;
    }
    return L.top->data;
}

Status Push(LinkStack *L,ElemType e)
{
    LNode *s=(LNode*)malloc(sizeof(LNode));
    s->data=e;
    s->next=L->top;
    L->top=s;
    L->count++;
    return OK;
}

LNode* Pop(LinkStack *L)
{
    if(StackIsEmpty(*L)){
        return ERROR;
    }
    LNode *temp;
    temp=L->top;
    L->top=L->top->next;
    L->count--;
    return temp;
}

Status PrintStack(LinkStack L)
{
    if(L.top==NULL){
        return ERROR;
    }
    while(L.top){
        printf("%c",L.top->data);
        L.top=L.top->next;
    }
    printf("\n");
    return OK;
}

1、中缀表达式转为后缀表达式

准备一个存放运算结果的数组和一个判断操作符的栈

从左往右扫描表达式

遇到数字,直接存入数组中;

遇到运算符,

​ 首先解决分母为0的问题,

​ 再判断栈如果为空,直接入栈,

​ 栈不为空,比较该运算符和此时栈顶元素的优先级

​ 高于,直接入栈;低于,依次出栈,直到高于栈顶元素的优先级;

遇到左括号,直接入栈;

遇到右括号,依次将栈顶元素存入数组,遇到左括号结束,再将左括号弹出;

最后表达式遍历完毕,依次将栈中的元素弹出存入数组中。

image-20230403142321916

1.1封装需要的方法

//判断输入的字符是否为数值
int is_Number(char c)
{
    if(c>='0'&&c<='9'){
        return 1;
    }
    return 0;
}

//判断输入的字符是否为运算符
int is_Operator(char c)
{
    if(c=='+'||c=='-'||c=='*'||c=='/'){
        return 1;
    }
    return 0;
}

//比较加减乘除的优先级
/*加减的优先级为1;乘除的优先级为2*/
int comp_Priority(char c)
{
    int level=0;
    switch(c)
    {
        case '+':
        case '-':
            level=1;
            break;
        case '*':
        case '/':
            level=2;
            break;
    }
    return level;
}

//判断是否为左括号
int is_Left(char c)
{
    if(c=='('){
        return 1;
    }
    return 0;
}

//判断是否为右括号
int is_Right(char c)
{
    if(c==')'){
        return 1;
    }
    return 0;
}

//初始化数组,每一位都放‘/0’
char result[MAX_SIZE]={0};

//存放后缀表达式的数组
void input(char c)
{
    static int index=0;
    result[index++]=c;
}

1.2 主方法

//将中缀表达式转换为后缀表达式
Status Trans_Postfix_Notation(char *str)
{
    int i;
    //初始化一个符号工作栈
    LinkStack L;
    InitStack(&L);
    i=0;
    while(str[i]!='\0'){
        //情况1:是数字
        if(is_Number(str[i])){
            if(is_Number(str[i+1])){
                input(str[i]);
            }
            //后一个可能是运算符或者括号
            if(!is_Number(str[i+1])){
                input(str[i]);
                input(' ');
            }
        }
        //情况2:是运算符
        /*如果栈为空,运算符直接压栈*/
        /*如果栈为不为空,要进栈的运算符与栈顶运算符比较优先级*/
        /*优先级高,继续压栈*/
        /*优先级低,出栈*/
        if(is_Operator(str[i])){
            if(str[i]=='/'&&str[i+1]=='0'){
                printf("表达式中分母不能为0.\n");
                return ERROR;
            }
            if(!StackIsEmpty(L)){
                    //比较优先级
                    /*1、要压入的,比栈顶的高,直接压入*/

                    /*2、要压入的,比栈顶的低*/
                    if(comp_Priority(str[i])<=comp_Priority(GetTop(L))){
                        while(!StackIsEmpty(L)&&comp_Priority(str[i])<=comp_Priority(GetTop(L))){
                            input(Pop(&L)->data);
                            input(' ');
                        }
                    }
                   Push(&L,str[i]);//两种情况公有的部分
                }
            if(StackIsEmpty(L)){
               Push(&L,str[i]);
              }
        }

        //情况3:是左括号
        if(is_Left(str[i])){
            Push(&L,str[i]);
        }

        //情况4:是右括号
        if(is_Right(str[i])){
            while(!is_Left(GetTop(L))){
                input(Pop(&L)->data);
                input(' ');
                if(StackIsEmpty(L)){
                    printf("表达式的括号不匹配.\n");
                    return ERROR;
                }
            }
            Pop(&L);//弹出匹配的左括号
        }

        //情况5:非法字符
        if(!is_Number(str[i])&&!is_Operator(str[i])&&!is_Left(str[i])&&!is_Right(str[i])){
            printf("存在非法字符.\n");
            return ERROR;
        }
        i++;
    }

    //情况6:字符串循环完毕
    while(!StackIsEmpty(L)){
        input(Pop(&L)->data);
        input(' ');
    }

    printf("%s",result);
    return OK;
}

2、计算后缀表达式的值

从左往右扫描表达式,

遇到数字就将其压入栈,注意如果是两位数,需要多取一次

遇到运算符说明可以计算,这时取出依次取出栈顶的两个元素进行运算符运算,

运算完毕,将计算结果再压入栈

直到栈中只留下最后一个元素

这个元素就是表达式的计算结果。

2.1 封装需要的方法

//将字符串转为整型
int string_to_int(char *temp)
{
    return atoi(temp);
}

//将字符类型转为整型
int char_to_int(char temp)
{
    return temp-'0';
}

//将整型转为字符类型
char int_to_char(int temp)
{
    return temp+'0';
}

int Calculator(int a,int b,char temp)
{
    int result2=0;
    switch(temp)
    {
    case '+':
        result2=a+b;
        break;
    case '-':
        result2=a-b;
        break;
    case '*':
        result2=a*b;
        break;
    case '/':
        result2=a/b;
        break;
    }
    return result2;
}

2.2 主方法

int comp_Rev_Polish_Notation()
{
    LinkStack S;//存放
    InitStack(&S);
    int i=0;
    int sum=0;//记录最终的结果
    int a,b;//需要进行运算的两个操作数
    int c;//保留两数的计算结果
    while(result[i]!='\0'){
        if(result[i]!=' '){
            if(is_Number(result[i])){
                if(!is_Number(result[i+1])){
                    Push(&S,result[i]);
                }
                if(is_Number(result[i+1])){//解决两位数的问题
                    a=char_to_int(result[i]);
                    b=char_to_int(result[i+1]);
                    c=a*10+b;
                    Push(&S,int_to_char(c));
                    i+=2;
                    continue;
                }
            }
            if(is_Operator(result[i])){
                a=char_to_int(Pop(&S)->data);
                b=char_to_int(Pop(&S)->data);
                c=Calculator(b,a,result[i]);
                Push(&S,int_to_char(c));
            }
        }
        i++;
    }
    if(S.count==1){
        sum=char_to_int(Pop(&S)->data);
    }
    return sum;
}

3、主函数

int main()
{
    char str[MAX_SIZE]={0};//存放手动输入的中缀表达式
    char ch;
    int i=0;
    int sum=0;//记录表达式的最终结果
    printf("链栈创建成功,请继续操作.\n");
    printf("\n==========================\n");
    printf("通过逆波兰表示法计算表达式的值.\n");
    printf("请输入一个中缀表达式:");
    while((ch=getchar())!='\n'){
        str[i]=ch;
        i++;
    }
    str[i]='\0';
    printf("\n");
    printf("对应的后缀表达式(逆波兰表达式)为:");
    Trans_Postfix_Notation(str);
    printf("\n");
    printf("\n");
    sum=comp_Rev_Polish_Notation();
    printf("表达式的值为:%d.\n",sum);
    printf("\n");
    printf("==========================\n");
    return 0;
}

程序源码

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

#define OK 1
#define ERROR 0

#define MAX_SIZE 100

typedef char ElemType;
typedef int Status;

typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode;

typedef struct LinkStack
{
    int count;
    struct LNode *top;
}LinkStack;

Status InitStack(LinkStack* L)
{
    L->top=(LNode*)malloc(sizeof(LNode));
    if(!L->top){
        return ERROR;
    }
    L->top=NULL;
    L->count=0;
    return OK;
}

Status StackIsEmpty(LinkStack L)
{
    if(L.count==0){
        return OK;
    }
    if(L.count!=0){
        return ERROR;
    }
    return OK;
}

ElemType GetTop(LinkStack L)
{
    if(StackIsEmpty(L)){
        return ERROR;
    }
    return L.top->data;
}

Status Push(LinkStack *L,ElemType e)
{
    LNode *s=(LNode*)malloc(sizeof(LNode));
    s->data=e;
    s->next=L->top;
    L->top=s;
    L->count++;
    return OK;
}

LNode* Pop(LinkStack *L)
{
    if(StackIsEmpty(*L)){
        return ERROR;
    }
    LNode *temp;
    temp=L->top;
    L->top=L->top->next;
    L->count--;
    return temp;
}

Status PrintStack(LinkStack L)
{
    if(L.top==NULL){
        return ERROR;
    }
    while(L.top){
        printf("%c",L.top->data);
        L.top=L.top->next;
    }
    printf("\n");
    return OK;
}

/*--------------------------------*/

//判断输入的字符是否为数值
int is_Number(char c)
{
    if(c>='0'&&c<='9'){
        return 1;
    }
    return 0;
}

//判断输入的字符是否为运算符
int is_Operator(char c)
{
    if(c=='+'||c=='-'||c=='*'||c=='/'){
        return 1;
    }
    return 0;
}

//比较加减乘除的优先级
/*加减的优先级为1;乘除的优先级为2*/
int comp_Priority(char c)
{
    int level=0;
    switch(c)
    {
        case '+':
        case '-':
            level=1;
            break;
        case '*':
        case '/':
            level=2;
            break;
    }
    return level;
}

//判断是否为左括号
int is_Left(char c)
{
    if(c=='('){
        return 1;
    }
    return 0;
}

//判断是否为右括号
int is_Right(char c)
{
    if(c==')'){
        return 1;
    }
    return 0;
}

//初始化数组,每一位都放‘/0’
char result[MAX_SIZE]={0};

//存放后缀表达式的数组
void input(char c)
{
    static int index=0;
    result[index++]=c;
}


//将中缀表达式转换为后缀表达式
Status Trans_Postfix_Notation(char *str)
{
    int i;
    //初始化一个符号工作栈
    LinkStack L;
    InitStack(&L);
    i=0;
    while(str[i]!='\0'){
        //情况1:是数字
        if(is_Number(str[i])){
            if(is_Number(str[i+1])){
                input(str[i]);
            }
            //后一个可能是运算符或者括号
            if(!is_Number(str[i+1])){
                input(str[i]);
                input(' ');
            }
        }
        //情况2:是运算符
        /*如果栈为空,运算符直接压栈*/
        /*如果栈为不为空,要进栈的运算符与栈顶运算符比较优先级*/
        /*优先级高,继续压栈*/
        /*优先级低,出栈*/
        if(is_Operator(str[i])){
            if(str[i]=='/'&&str[i+1]=='0'){
                printf("表达式中分母不能为0.\n");
                return ERROR;
            }
            if(!StackIsEmpty(L)){
                    //比较优先级
                    /*1、要压入的,比栈顶的高,直接压入*/

                    /*2、要压入的,比栈顶的低*/
                    if(comp_Priority(str[i])<=comp_Priority(GetTop(L))){
                        while(!StackIsEmpty(L)&&comp_Priority(str[i])<=comp_Priority(GetTop(L))){
                            input(Pop(&L)->data);
                            input(' ');
                        }
                    }
                   Push(&L,str[i]);//两种情况公有的部分
                }
            if(StackIsEmpty(L)){
               Push(&L,str[i]);
              }
        }

        //情况3:是左括号
        if(is_Left(str[i])){
            Push(&L,str[i]);
        }

        //情况4:是右括号
        if(is_Right(str[i])){
            while(!is_Left(GetTop(L))){
                input(Pop(&L)->data);
                input(' ');
                if(StackIsEmpty(L)){
                    printf("表达式的括号不匹配.\n");
                    return ERROR;
                }
            }
            Pop(&L);//弹出匹配的左括号
        }

        //情况5:非法字符
        if(!is_Number(str[i])&&!is_Operator(str[i])&&!is_Left(str[i])&&!is_Right(str[i])){
            printf("存在非法字符.\n");
            return ERROR;
        }
        i++;
    }

    //情况6:字符串循环完毕
    while(!StackIsEmpty(L)){
        input(Pop(&L)->data);
        input(' ');
    }

    printf("%s",result);
    return OK;
}

//封装的函数

//将字符串转为整型
int string_to_int(char *temp)
{
    return atoi(temp);
}

//将字符类型转为整型
int char_to_int(char temp)
{
    return temp-'0';
}

//将整型转为字符类型
char int_to_char(int temp)
{
    return temp+'0';
}

int Calculator(int a,int b,char temp)
{
    int result2=0;
    switch(temp)
    {
    case '+':
        result2=a+b;
        break;
    case '-':
        result2=a-b;
        break;
    case '*':
        result2=a*b;
        break;
    case '/':
        result2=a/b;
        break;
    }
    return result2;
}

int comp_Rev_Polish_Notation()
{
    LinkStack S;//存放
    InitStack(&S);
    int i=0;
    int sum=0;//记录最终的结果
    int a,b;//需要进行运算的两个操作数
    int c;//保留两数的计算结果
    while(result[i]!='\0'){
        if(result[i]!=' '){
            if(is_Number(result[i])){
                if(!is_Number(result[i+1])){
                    Push(&S,result[i]);
                }
                if(is_Number(result[i+1])){//解决两位数的问题
                    a=char_to_int(result[i]);
                    b=char_to_int(result[i+1]);
                    c=a*10+b;
                    Push(&S,int_to_char(c));
                    i+=2;
                    continue;
                }
            }
            if(is_Operator(result[i])){
                a=char_to_int(Pop(&S)->data);
                b=char_to_int(Pop(&S)->data);
                c=Calculator(b,a,result[i]);
                Push(&S,int_to_char(c));
            }
        }
        i++;
    }
    if(S.count==1){
        sum=char_to_int(Pop(&S)->data);
    }
    return sum;
}


int main()
{
    char str[MAX_SIZE]={0};//存放手动输入的中缀表达式
    char ch;
    int i=0;
    int sum=0;//记录表达式的最终结果
    printf("链栈创建成功,请继续操作.\n");
    printf("\n==========================\n");
    printf("通过逆波兰表示法计算表达式的值.\n");
    printf("请输入一个中缀表达式:");
    while((ch=getchar())!='\n'){
        str[i]=ch;
        i++;
    }
    str[i]='\0';
    printf("\n");
    printf("对应的后缀表达式(逆波兰表达式)为:");
    Trans_Postfix_Notation(str);
    printf("\n");
    printf("\n");
    sum=comp_Rev_Polish_Notation();
    printf("表达式的值为:%d.\n",sum);
    printf("\n");
    printf("==========================\n");
    return 0;
}

运行截图

image-20230403163016851


🚀先看后赞,养成习惯!🚀

🚀 先看后赞,养成习惯!🚀

🎈觉得文章写得不错的老铁们,点赞评论关注走一波!谢谢啦!🎈


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值