网上有很多关于中缀转后缀的文章,很多文章或多或少都有bug,包括一些教学视频,经过本人无数次测试,保证下面的代码运算结果的正确性前提是你写的中缀表达式是正确的哈,没有做中缀表达式是否正确的的完整性校验。采用的c语言编写的哈。

中缀、后缀表达式区别

中缀表达式:(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法

后缀表达式:后缀表达式,指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)

可以通过 2个表达式计算的结果,证明是否转换正确

中缀、转后缀规则

规则摘抄大话数据结构中的描述 ,中缀表达式转后缀表达式规则:

从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;
若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级低于栈顶符号(乘除优先加减,)

则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止

中缀、转后缀规则分析

首先判断字符是否是数字

  1. 是数字直接输出
  2. 非数字再对字符进行分析
    1. 右括号,依次弹栈并输出符号,直到遇到(左括号
    2. 字符优先级低于栈顶符号依次弹栈直到遇到字符优先级高于栈顶符号或者遇到左括号或者空栈,当前符号再才进(压)栈(如果和栈顶符号优先级一样也要先栈顶符号也要先弹栈,因为优先级一样运算顺序是从左往右!这一点很重要,很多网上的文章或者视频 都是这一点出错了!)
      1. +  - 符号是优先级最低的,一定是先依次弹栈再压栈
      2. * / 符号优先级只比 + - 高,栈空或栈顶为( + - 符号栈才直接压栈,其他情况先依次弹栈再压栈
    3. 左括号,左括号(直接压栈,如果栈顶元素为左括号(,该字符同样直接压栈!这点很重要!

中缀、转后缀函数局部代码

将用户输入放到一个字符串,将转换得到后缀表达式同样放到一个字符串中,方便封装进行复用。

/*
将中缀表达式转成后缀表达式
*/
char* MidExpToAfterExp(const char* midExp)
{//后缀表达式char* afterExp = (char*)malloc(sizeof(char)*EXPRESS_MAX);memset(afterExp, 0, EXPRESS_MAX);int j = 0;//afterExp下标int k = 0;//preExp下标SeqStack stack;// + - * / ( )符号栈InitStack(&stack);char numBuf[10] = { 0 };//连续的数字不能超过10位,也就是中缀表达式中数字不能超过10位char ch = 0;int numIndex = 0;//numBuf 下标while (midExp[k]){ch = midExp[k++];//忽略中缀表达式中的空格if (ch == ' '){continue;}//回车代表中缀输入完毕if ('\n' == ch){break;}//1、若是数字就输出if (ch >= '0' && ch <= '9'){//如果输入连续的数字,不是连续的数字 循环完毕 会走 2、非数字while (((ch >= '0' && ch <= '9') || '.' == ch) && numIndex < 10){numBuf[numIndex++] = ch;afterExp[j++] = ch;ch = midExp[k++];}numBuf[numIndex] = 0;afterExp[j++] = ' ';}//回车代表中缀输入完毕if ('\n' == ch){break;}//忽略中缀表达式中的空格else if (' ' == ch){continue;}//2、非数字else if (ch < '0' || ch > '9'){numIndex = 0;//进入这个if 数字肯定不连续了,下标重置为0//右括号一定弹栈if (')' == ch){int flag = 1;//判断中缀表达式中括号是否匹配,如果成对出现while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){flag = 0;//走到这里说明是()括号成对出现break;}afterExp[j++] = ch;afterExp[j++] = ' ';}if (flag){printf("中缀表达式输入错误\n");exit(0);}}// + - 符号是优先级最低的,一定是先依次弹栈再压栈。else if ('+' == ch || '-' == ch){EleType top;GetTop(&stack, &top);//栈空或者栈顶为左括号 直接压栈if (IsEmptyStack(&stack)|| '(' == top){push(&stack, ch);}else{char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){//不是因为)右括号而弹栈,多弹的(左括号压回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}}// * / 符号优先级只比 + -高,栈空或栈顶为(+-符号栈才直接压栈,其他情况先依次弹栈再压栈else if ('*' == ch || '/' == ch){EleType top;GetTop(&stack, &top);//栈空或者栈顶为左括号同样直接压栈if (IsEmptyStack(&stack) || '(' == top || '-' == top || '+' == top){push(&stack, ch);}else if ('*' == top || '/' == top){char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch || '-' == ch || '+' == ch){//不是因为)右括号而弹栈 * / 优先级高于栈顶 + - 就不弹栈了,多弹的压回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}} else if ( '(' == ch){push(&stack, ch);}else{printf("中缀表达式输入错误\n");exit(0);}}}//符号栈内容不为空 依次出栈并打印while (!IsEmptyStack(&stack)){pop(&stack, &ch);afterExp[j++] = ch;afterExp[j++] = ' ';}return afterExp;
}

完整代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define STACK_INIT_SIZE 20   // 栈初始容量
#define STACK_INCREMENT 10   //栈满后,每次扩充的容量
#define EXPRESS_MAX 1024 //后缀表达式 长度不能超过1024
typedef int Status;
typedef char EleType;typedef struct SeqStack
{EleType* top;//栈顶指针EleType* base;//栈底指针int stackSize;//栈容量
}SeqStack;
//初始化栈
Status InitStack(SeqStack* stack)
{//开辟空间stack->base = stack->top = (EleType*)malloc(STACK_INIT_SIZE * sizeof(EleType));if (!stack->base){exit(0);}stack->stackSize = STACK_INIT_SIZE;return OK;
}
//压栈
Status push(SeqStack* stack, EleType e)
{if (stack == NULL){return ERROR;}//压栈之前检测容量是否足够if (stack->top - stack->base == stack->stackSize){//超出容量 进行扩容,使用realloc函数,会拷贝原内存内容stack->base = (EleType*)realloc(stack->base, stack->stackSize + STACK_INCREMENT);if (!stack->base){exit(0);}stack->top = stack->base + stack->stackSize;stack->stackSize += STACK_INCREMENT;}*stack->top = e;stack->top++;return OK;
}
//弹栈
Status pop(SeqStack* stack, EleType *e)
{if (stack == NULL || e == NULL){return ERROR;}//空栈if (stack->top == stack->base){return ERROR;}*stack->top--;*e = *stack->top;return OK;
}
/*
获取栈顶元素
*/
Status GetTop(SeqStack* stack, EleType *e) {if (NULL == stack) {return ERROR;}*e = *(stack->top - 1);return OK;
}
/*
判断栈是否为空
*/
int IsEmptyStack(SeqStack* stack) {if (NULL == stack) {return ERROR;}if (stack->top == stack->base) {return TRUE;}return FALSE;
}
/*
销毁栈
*/
Status DestroyStack(SeqStack* stack)
{if (NULL == stack) {return ERROR;}//销毁栈 是释放栈在内存中占用的空间资源if (!stack->base){free(stack->base);}stack->top = stack->base = NULL;stack->stackSize = 0;return OK;
}
/*
将中缀表达式转成后缀表达式
*/
char* MidExpToAfterExp(const char* midExp)
{//后缀表达式char* afterExp = (char*)malloc(sizeof(char)*EXPRESS_MAX);memset(afterExp, 0, EXPRESS_MAX);int j = 0;//afterExp下标int k = 0;//preExp下标SeqStack stack;// + - * / ( )符号栈InitStack(&stack);char numBuf[10] = { 0 };//连续的数字不能超过10位,也就是中缀表达式中数字不能超过10位char ch = 0;int numIndex = 0;//numBuf 下标while (midExp[k]){ch = midExp[k++];//忽略中缀表达式中的空格if (ch == ' '){continue;}//回车代表中缀输入完毕if ('\n' == ch){break;}//1、若是数字就输出if (ch >= '0' && ch <= '9'){//如果输入连续的数字,不是连续的数字 循环完毕 会走 2、非数字while (((ch >= '0' && ch <= '9') || '.' == ch) && numIndex < 10){numBuf[numIndex++] = ch;afterExp[j++] = ch;ch = midExp[k++];}numBuf[numIndex] = 0;afterExp[j++] = ' ';}//回车代表中缀输入完毕if ('\n' == ch){break;}//忽略中缀表达式中的空格else if (' ' == ch){continue;}//2、非数字else if (ch < '0' || ch > '9'){numIndex = 0;//进入这个if 数字肯定不连续了,下标重置为0//右括号一定弹栈if (')' == ch){int flag = 1;//判断中缀表达式中括号是否匹配,如果成对出现while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){flag = 0;//走到这里说明是()括号成对出现break;}afterExp[j++] = ch;afterExp[j++] = ' ';}if (flag){printf("中缀表达式输入错误\n");exit(0);}}// + - 符号是优先级最低的,一定是先依次弹栈再压栈。else if ('+' == ch || '-' == ch){EleType top;GetTop(&stack, &top);//栈空或者栈顶为左括号 直接压栈if (IsEmptyStack(&stack)|| '(' == top){push(&stack, ch);}else{char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){//不是因为)右括号而弹栈,多弹的(左括号压回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}}// * / 符号优先级只比 + -高,栈空或栈顶为(+-符号栈才直接压栈,其他情况先依次弹栈再压栈else if ('*' == ch || '/' == ch){EleType top;GetTop(&stack, &top);//栈空或者栈顶为左括号同样直接压栈if (IsEmptyStack(&stack) || '(' == top || '-' == top || '+' == top){push(&stack, ch);}else if ('*' == top || '/' == top){char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch || '-' == ch || '+' == ch){//不是因为)右括号而弹栈 * / 优先级高于栈顶 + - 就不弹栈了,多弹的压回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}} else if ( '(' == ch){push(&stack, ch);}else{printf("中缀表达式输入错误\n");exit(0);}}}//符号栈内容不为空 依次出栈并打印while (!IsEmptyStack(&stack)){pop(&stack, &ch);afterExp[j++] = ch;afterExp[j++] = ' ';}return afterExp;
}int main(int argc, char *argv[])
{while (1){printf("请输入中缀表达式(#表示退出):");//中缀表达式char* midExp = (char*)malloc(sizeof(char)*EXPRESS_MAX) ;memset(midExp, 0, EXPRESS_MAX);fgets(midExp, 1024, stdin);//midExp 包含换行符if ('#' == midExp[0]){break;}//后缀表达式char* afterExp= MidExpToAfterExp(midExp);printf("对应的后缀表达式:%s\n", afterExp);}return 0;
}

验证结果

进行复杂性验证哈,确保程序正确性。如何验证正确性呢?请看 后缀表达式运算规则,如果根据后缀表达式 的计算结果和中缀表达式计算结果一致就说明转换正确如果不正确,你来找我

栈应用:中缀表达式转后缀表达式相关推荐

  1. 数据结构——栈——中缀表达式和后缀表达式

    什么是中缀表达式,什么是后缀表达式 我们一般看见的多项式计算都是中缀表达式构成的:1+2*3+4/3 类似这种,为什么说是中缀呢?因为它的计算符号都是在两个数中间的. 那么自然而然的明白了后缀表达式是 ...

  2. 栈应用(中缀表达式转后缀表达式并计算后缀表达式的值)

    [0]README 0.1) 本文旨在总结 中缀表达式转后缀表达式并计算后缀表达式的值 的步骤,并给出源代码实现: 0.2) 本文中涉及到的源代码均为原创,是对中缀转后缀和计算后缀的简单实现,(旨在理 ...

  3. 数据结构 - 栈 (逆波兰计算器)(栈的三种表达式)(前缀、中缀和后缀表达式,后缀也叫逆波兰表达式)(中缀表达式转后缀表达式实现步骤及完整代码)

    栈的三种表达式:前缀.中缀和后缀表达式,后缀也叫逆波兰表达式 前缀(波兰表达式) 中缀(对人来讲很好理解,对于计算机来讲就方便了,一般会把中缀表达式转换成后缀表达式) 后缀(逆波兰表达式) 计算过程 ...

  4. 使用栈实现中缀表达式转为后缀表达式和后缀表达式的求解

    书籍在线网址http://interactivepython.org/runestone/static/pythonds/index.html 中文翻译书籍:https://facert.gitboo ...

  5. java利用栈求复杂表达式_java中的栈Stack的基本使用和应用(二) ——利用栈计算合法的算术表达,中缀表达式转后缀表达式...

    利用栈Stack计算合法的算术表达式 限定的算术表达式求值问题:包含 "+"."-"."*"."/" .正整数和圆括号的 ...

  6. 数据结构(3) 第三天 栈的应用:就近匹配/中缀表达式转后缀表达式 、树/二叉树的概念、二叉树的递归与非递归遍历(DLR LDR LRD)、递归求叶子节点数目/二叉树高度/二叉树拷贝和释放...

    01 上节课回顾 受限的线性表 栈和队列的链式存储其实就是链表 但是不能任意操作 所以叫受限的线性表 02 栈的应用_就近匹配 案例1就近匹配: #include <stdio.h> in ...

  7. java中缀表达式转后缀表达式(逆波兰算法)

    四则运算是栈的重要应用之一 中缀表达式转后缀表达式(逆波兰算法)过程 从左到右遍历中缀表达式 数字直接输出为后缀表达式一部分 如果是符号,则判断与栈顶元素的优先级 高于栈顶元素优先级直接入栈 低于或等 ...

  8. java中缀表达式转后缀表达式_数据结构Java实现06----中缀表达式转换为后缀表达式...

    本文主要内容: 表达式的三种形式 中缀表达式与后缀表达式转换算法 一.表达式的三种形式: 中缀表达式:运算符放在两个运算对象中间,如:(2+1)*3.我们从小做数学题时,一直使用的就是中缀表达式. 后 ...

  9. 数据结构实验——中缀表达式转为后缀表达式

    一.实验内容: 编写程序,实现中缀表达式化为后缀式输出. 已知中缀表达式中操作数全部用小写英文字母表示,运算符只含有+, -, *, /四种,定界符只有( )以及结束符#. 二.程序源代码: 运行示例 ...

最新文章

  1. CMU赵越 关于异常检测的分享!
  2. 【机器学习入门到精通系列】推荐系统之协同过滤算法
  3. Python爬虫速度很慢?并发编程了解一下吧
  4. 高质量 Node.js 微服务的编写和部署
  5. 《Linux设备驱动开发详解》学习笔记一
  6. 巴赛尔协议与贷款产品利率解析
  7. 浪潮gs设置连接服务器信息,浪潮GS系统客户端设置方案
  8. Citespace和vosviewer【理工、经管、法学、教育、农学、文史、医学、艺术】
  9. h5/uni-app打开手机app,没有则跳转到商店下载
  10. PaddlePaddle入门实践——手写数字识别
  11. 前端移动端开发(基础)
  12. 混合现实:手柄定位不准或者经常性丢失
  13. 微信小程序实现列表项左滑删除效果
  14. Unity开发VR项目——问题集锦
  15. jquery的$().each(function(i){})和和$.each(,function(i,n){})的区别和用法
  16. libxml2 使用教程
  17. 小破练习-嵌套循环及列表
  18. 手写迷你版HashMap
  19. Windows下编译WebRTC
  20. mat 释放_Opencv - 释放内存将cv :: Mat引用计数器更改为零

热门文章

  1. 1.9 _07 不与最大数相同的数字之和 python
  2. RTX5 | 内存池04 - 共享内存用于线程之间的通讯(阻塞方式)- 使用信号量
  3. STM32H743-梳理ADC模数转换器在CubeMX上的配置
  4. Qt文档阅读笔记-moc工具使用及其理论(moc工具如何添加到makefile中)
  5. mysql 建表语句 stored as_Druid 解析Hive建表语句解析报错
  6. java 分享巧克力_[leetcode 双周赛 11] 1231 分享巧克力
  7. 轻松的java,轻松进行Java Portlets
  8. panda python_12个很棒的Pandas和NumPy函数,让分析事半功倍
  9. flstudio插件找不到_【干货】音频插件完全指引手册
  10. c语言形式参数若为b 4,2016年计算机二级c语言题库