因为在学校实在是太闲了,所以写了一个表达式求值的C语言程序,希望大佬可以多多指正。

基本思路:

就像把大象装进冰箱一样,我们需要三步进行表达式的求值工作。

  • 输入一个中缀表达式(就是平常我们见的表达式)
  • 将中缀表达式转换为后缀表达式
  • 根据后缀表达式求值。

第一步:

输入一个中缀表达式比较简单,不过为了编写代码更加简单,这里对输入的表达式进行一些规范

  • 所有的输入字符与数字之间,采取空格进行分开
  • 不可以对乘号进行省略
  • 数字后面要跟一个空格再输入操作符。

第二步:

中缀表达式转后缀表达式的基本过程为:从头到尾读取中缀表达式的每个对象,对不同的对象按照不同的情况处理,分为以下六种情况:

  • 如果是空格,认为是分割符,不处理
  • 如果是运算数,直接输出
  • 如果是左括号,则将其压入堆栈中
  • 如果是右括号,表明括号内的中缀表达式已经扫描完毕,将栈顶的运算符弹出并输出,直到遇到左括号(左括号不输出)
  • 如果遇到运算符,如果现在栈空,则直接将运算符放入栈中,若不空,则将此运算符与栈顶的运算符进行优先级比较,如果该运算符的优先级小于等于栈顶运算符的话,则将栈顶运算符输出,并再次将此运算符与新的栈顶运算符进行比较,直到该运算符的优先级大于栈顶运算符的优先级为止,然后将该运算符压栈
  • 若中缀表达式中的各个元素处理完毕,则把堆栈中存留的运算符一并输出。

执行完所有的流程,我们就输出了一个中缀表达式。


当然了,在实际实现的时候,我们对格式依然有所要求。后缀表达式不同于中缀表达式,后缀表达式中可能会出现好多个数字连在一起的情况,所以,对连续输出的数字,我们要给中间加上空格进行分割,以此区分是一个两位的十进制数,还是两个一位的十进制数。

第三步:

根据后缀表达式求值,我想大家学习了栈的知识,并弄明白后缀表达式是什么的话,就可以非常容易理解如何使用栈对后缀表达式进行求值,详情请看我的另一篇博客 点我看栈的实现以及后缀表达式求值.


三步都弄懂了,如何将这三步联合在一起呢?

在介绍之前,先吐槽一下C语言,连个能直接调的栈都没有,如果我要调用两个不一样的栈,一个装int,一个装char,那么我还需要写两套定义,否则在一个程序中没办法实现。(可能可以实现,但我不会,我很抱歉)

联合

首先我们将第二步和第三步的内容进行封装,自定义两个头文件,并对内容进行实现,在定义的过程中,我发现有一些定义是重复的,所以我们将重复定义的东西放到另外一个头文件中。

文件名 作用
same.h 定义一些重复的宏
TransformationToInfixExpression.h 定义转换为后缀表达式的头文件
ExpressionEvaluation.h 定义后缀表达式求值的头文件
TransformationToInfixExpression.c 实现前面同名的头文件
ExpressionEvaluation.c 实现前面同名的头文件
test.c 主函数,用于实现第一步

same.h

#define MAXOP 100            /*操作数序列可能的最大长度*/
#define INFINITY 1e9        /*代表正无穷*/
#define ERROR -INFINITY
typedef int Position;
typedef char ElementType1;
typedef double ElementType2;
struct SNode1{ElementType1 *Data;       /*存储元素的数组*/Position Top;            /*栈顶指针*/    int MaxSize;            /*堆栈最大容量*/
};
struct SNode2{ElementType2 *Data;       /*存储元素的数组*/Position Top;            /*栈顶指针*/    int MaxSize;            /*堆栈最大容量*/
};

TransformationToInfixExpression.h

//TransformationToInfixExpression.h
#ifndef _TRANSFORMATIONTOINFIXEXPRESSION_H_
#define _TRANSFORMATIONTOINFIXEXPRESSION_H_//结构体和函数声明....typedef struct SNode1 *PtrToSNode1;typedef PtrToSNode1 Stack1;typedef char ElementType1;//1. 将一个中缀表达式转换为后缀表达式void TransformationToInfixExpression(char* Expr, char* Aim);//判断字符的优先级int Priority(char a,char b);Stack1 CreateStack1(int MaxSize);int IsFull1(Stack1 S);int Push1(Stack1 S,ElementType1 X);int IsEmpty1(Stack1 S);ElementType1 Pop1(Stack1 S);ElementType1 Peek1(Stack1 S);#endif

ExpressionEvaluation.h

//ExpressionEvaluation.h
//条件编译
#ifndef _EXPRESSIONEVALUATION_H_
#define _EXPRESSIONEVALUATION_H_ //结构体和函数声明....typedef enum {true,false} bool;typedef enum {num, opr, end} Type;typedef struct SNode2 *PtrToSNode2;typedef PtrToSNode2 Stack2;typedef double ElementType2;Stack2 CreateStack2(int MaxSize);bool IsFull2(Stack2 S);bool Push2(Stack2 S,ElementType2 X);bool IsEmpty2(Stack2 S);ElementType2 Pop2(Stack2 S);ElementType2 Peek2(Stack2 S);Type GetOp(char * Expr, int * start,char * str);ElementType2 PostfixExp(char* Expr);#endif

TransformationToInfixExpression.c

#include"TransformationToInfixExpression.h"
#include"same.h"
#include"ExpressionEvaluation.h"
#include<string.h>
#include<ctype.h>
#include<stdio.h>
#include<stdlib.h>
Stack1 CreateStack1(int MaxSize){Stack1 S = (Stack1)malloc(sizeof(Stack1));S->Data = (ElementType1*)malloc(MaxSize*sizeof(ElementType1));S->Top = -1;S->MaxSize = MaxSize;return S;
}
int IsFull1(Stack1 S){return (S->Top == S->MaxSize - 1);
}
int Push1(Stack1 S,ElementType1 X){if(IsFull1(S)){printf("堆栈满\n");return 0;}else{S->Data[++(S->Top)] = X;return 1;}
}
int IsEmpty1(Stack1 S){return (S->Top == -1);
}
ElementType1 Pop1(Stack1 S){if(IsEmpty1(S)){printf("堆栈空1\n");return (ElementType1)ERROR;}else{return S->Data[(S->Top)--];}
}
ElementType1 Peek1(Stack1 S){if(IsEmpty1(S)){printf("堆栈空2\n");return (ElementType1)ERROR;}else{return S->Data[(S->Top)];}
}void TransformationToInfixExpression(char* Expr, char* Aim){int n = strlen(Expr);Stack1 S = CreateStack1(MAXOP);int j = 0;for (int i = 0; i < n; i++){if (Expr[i] == ' '){if(j != 0 && Aim[j-1] != ' '){Aim[j++] = Expr[i];}continue;} else if(isdigit(Expr[i]) || Expr[i] == '.'){Aim[j++] = Expr[i];} else if(Expr[i] == '('){Push1(S,Expr[i]);} else if(Expr[i] == ')'){char c = Pop1(S);while(c != '('){Aim[j++] = c;Aim[j++] = ' ';c = Pop1(S);}} else {if(!IsEmpty1(S)){char c = Peek1(S);while(Priority(Expr[i],c) <= 1){Aim[j++] = Pop1(S);Aim[j++] = ' ';if(!IsEmpty1(S)){c = Peek1(S);}else{break;}}}Push1(S,Expr[i]);}}Aim[j++] = ' ';while(!IsEmpty1(S)){Aim[j++] = Pop1(S);Aim[j++] = ' ';}
}int Priority(char a,char b){/*a==b  0;a<b   1;a>b   2;*/if(a == '*' || a == '/'){if(b == '*' || b == '/'){return 0;}else{return 2;}}else if(a == '+' || a == '-'){if(b == '*' || b == '/'){return 1;}else if(b == '+' || b == '-'){return 0;}else {return 2;}}
}

ExpressionEvaluation.c

//这个程序是利用堆栈求后缀表达式的值
#include"ExpressionEvaluation.h"
#include"same.h"
#include"TransformationToInfixExpression.h"
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
Stack2 CreateStack2(int MaxSize){Stack2 S = (Stack2)malloc(sizeof(Stack2));S->Data = (ElementType2*)malloc(MaxSize*sizeof(ElementType2));S->Top = -1;S->MaxSize = MaxSize;return S;
}
bool IsFull2(Stack2 S){return (S->Top == S->MaxSize - 1);
}
bool Push2(Stack2 S,ElementType2 X){if(IsFull2(S)){printf("堆栈满\n");return false;}else{S->Data[++(S->Top)] = X;return true;}
}
bool IsEmpty2(Stack2 S){return (S->Top == -1);
}
ElementType2 Pop2(Stack2 S){if(IsEmpty2(S)){printf("堆栈空\n");return (ElementType2)ERROR;}else{return S->Data[(S->Top)--];}
}
ElementType2 Peek2(Stack2 S){if(IsEmpty2(S)){printf("堆栈空2\n");return (ElementType2)ERROR;}else{return S->Data[(S->Top)];}
}Type GetOp(char * Expr, int * start,char * str){/*从*start开始读下一个对象(操作数或者操作符),并保存在字符串str中*/int i = 0;/*跳过表达式前的空格*/while((str[0] = Expr[(*start)++])==' ');while(str[i]!=' ' && str[i] != '\0')str[++i] = Expr[(*start)++];if(str[i] == '\0')         /*如果读到输入的结尾*/(*start)--;                /*start指向结束符*/str[i] = '\0';             /*结束一个对象的获取*/if(i == 0) return end;       /*读到了结束*//*如果str[0]是数字,或者是符号跟个数字*/else if(isdigit(str[0]) || isdigit(str[1]))return num; /*表示str中存的仅仅是一个数字*/elsereturn opr;  /*表示str中存的是一个表达式*/
}
ElementType2 PostfixExp(char* Expr){Stack2 S;Type T;ElementType2 Op1,Op2;char str[MAXOP];int start = 0;/*申请一个新的堆栈*/S = CreateStack2(MAXOP);Op1 = Op2 = 0;while((T = GetOp(Expr,&start,str))!=end){/*当未读到结束时*/if(T == num){Push2(S,atof(str));} else {if(!IsEmpty2(S)) Op2 = Pop2(S);else Op2 = INFINITY;if(!IsEmpty2(S)) Op1 = Pop2(S);else Op2 = INFINITY;switch(str[0]){case'+':Push2(S,Op1 + Op2);break;case'*':Push2(S,Op1 * Op2);break;case'-':Push2(S,Op1 - Op2);break;case'/':if(Op2 != 0.0)/*检查除法的分母是不是等于0*/Push2(S,Op1 / Op2);else{printf("错误:除法分母为0\n");Op2 = INFINITY;}break;default:printf("错误:未知运算符:%s\n",str);Op2 = INFINITY;break;}if(Op2 == INFINITY) break;}}if(Op2 <INFINITY)/*处理完了表达式*/if(!IsEmpty2(S))/*而此时堆栈正常*/Op2 = Pop2(S);else Op2 = INFINITY;    /*否则标记错误*/free(S); /*释放堆栈*/return Op2;
}

test.c

#include"ExpressionEvaluation.h"
#include"TransformationToInfixExpression.h"
#include"same.h"
#include<stdio.h>
int main(){printf("请输入中缀表达式:\n");char Expr[MAXOP] = {0};char Aim[MAXOP] = {0};gets(Expr);TransformationToInfixExpression(Expr,Aim);printf("转换的后缀表达式为:%s\n",Aim);double r =  PostfixExp(Aim);printf("计算的结果为:%.4lf\n",r);
}

接下来就大功告成了,对这几个C文件进行联调,即可运行最后的程序,我们看一下效果吧 ^ - ^

效果:

编译命令是第一行:这里报错是因为gets已经不安全了,这里建议使用fgets,这里就不管了,不影响我们正常使用。


执行test文件:

到这里我们就可以输入一个我们看得懂的表达式,然后直接输出结果了。

觉得我写的还不错的话,希望可以点个赞哦,如果有更好的方案的话,也欢迎多多指教哦。


  • 思路和部分代码参考《数据结构(第二版)》 — 高等教育出版社

中缀表达式转后缀表达式并求值相关推荐

  1. 信息竞赛进阶指南--中缀表达式转后缀表达式并求值(模板)

    // 后缀表达式转中缀表达式,同时求值,O(n)// 数值栈 vector<int> nums; // 运算符栈 vector<char> ops;// 优先级 int gra ...

  2. C++代码实现中缀表达式求值(基于中缀表达式转后缀表达式)

    C++代码实现中缀表达式求值(基于中缀表达式转后缀表达式) 样例输入:3*(2+5) 样例输出:21 代码:#include <bits/stdc++.h> using namespace ...

  3. 数据结构 - 拓展突破(C++实现中缀表达式转前缀表达式,中缀表达式转后缀表达式,前缀表达式求值,中缀表达式求值)

    文章目录 1. C++中缀表达式转后缀表达式 2. C++中缀表达式转前缀表达式 3. C++后缀表达式求值 4. C++前缀表达式求值 1. C++中缀表达式转后缀表达式 输入中缀表达式样例: 2+ ...

  4. 数据结构中缀表达式转后缀表达式与后缀表达式的求值实训报告_动图+源码,演示 Java 中常用数据结构执行过程及原理...

    程序员的成长之路互联网/程序员/成长/职场 关注 阅读本文大概需要 3.7 分钟. 作者:大道方圆cnblogs.com/xdecode/p/9321848.html 最近在整理数据结构方面的知识, ...

  5. 利用stack结构,将中缀表达式转换为后缀表达式并求值的算法实现

    #!/usr/bin/env python # -*- coding: utf-8 -*-# learn <<Problem Solving with Algorithms and Dat ...

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

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

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

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

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

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

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

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

最新文章

  1. firefox固定为应用标签的功能很好用
  2. jQuery 插入元素
  3. BZOJ 3504: [Cqoi2014]危桥 [最大流]
  4. python中删除字典中所有元素的函数_在python中,按值删除字典项的最佳方法是什么?...
  5. MyBatis-19MyBatis代码生成器-XML配置详解
  6. leetcode 561. 数组拆分 I(Java版)
  7. Docker启动容器时出现错误
  8. 14 MM配置-BP业务伙伴-定义供应商科目组和字段选择
  9. python常见面试题(三)
  10. java中虚拟机命令:jstack使用方法
  11. 企业网盘居然支持高速局域网文件传输工具(速度可达20M)
  12. CRC校验 与 模2运算
  13. 从Controller注解切入了解spring注解原理
  14. couchbase php,轻松搞定|将PHP和Couchbase应用部署为Docker
  15. Tilera吴晓东:2013年要做成三百多个核
  16. 使用MD5加密的登陆demo
  17. 泰拉瑞亚 服务器linux,Linux/CentOS7搭建泰拉瑞亚原版/mod服务器教程
  18. SerDes结构之发送端前馈均衡技术(FFE)
  19. 如何理解CPU卡内部认证与外部认证
  20. Vue如何使用ECharts

热门文章

  1. C嘎嘎~~[类 中篇]
  2. C:/WINDOWS/system32/drivers/etc/hosts 文件有什么作用
  3. 极客战记 --沙漠 金色幻影解法
  4. linux能用airport吗_Linux 常用命令笔记-2
  5. JAVA获取股票实时KDJ_Java从网络获取股票实时数据,2种方法webservice和javascript
  6. 系统性能提升的经验和方法
  7. NPOI读取xls和xlsx格式
  8. 【算法】逻辑题算法题语言特性(集合贴1)
  9. C#常用基础知识总结(B/S和C/S的异同属于个人整理)
  10. go语言_官方文档 godoc