C语言 | 计算器实现(中缀表示法/后缀表示法)
————————————————————————————————————————————
实现原理:
每个操作数都被依次压入栈中,当一个运算符到达时,从栈中弹出相应数目的操作数(对于二元运算符来说是两个操作数),把该运算符作用于弹出的操作数,并把运算结果再压入栈中
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
计算器(后缀表达式)
相关知识:
后缀表达式(逆波兰表示法):在逆波兰中,所有运算符都跟在操作数后面,如下:(1 - 2) *(4 + 5) 采用逆波兰表示法表示为:1 2 - 4 5 + *,不需要圆括号,只要知道每个运算符需要几个操作数就不会引起歧义
实现功能:
输入后缀表达式,以换行结束,计算四则运算结果。
对于 1 2 - 4 5 + * 来说,首先把1和2压入到栈中,再用两者之差-1取代它们;然后将4和5压入到栈中,再用两者之和9取代它们。最后从栈中取出栈顶的-1和9,并把它们的积-9压入到栈顶。到达输入行的末尾时,把栈顶的值弹出来并打印。
伪代码:
while 读入值不为换行时
if 是数字
压入栈中
else if 是运算符
弹出两个运算数,计算并压栈
else 输入错误并退出
end if
读入值
弹出最终结果并打印
实现代码:
/* 实现功能:输入后缀表达式,以换行结束,计算四则运算结果 */
/* 这种后缀表示法只需要一个栈就可以了,遇到符号则弹运算数,但是中缀就不一样 */
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define STACK_INIT_SIZE 100
#define STACKINCREAMENT 10
typedef int Status;
typedef char SElemType;
typedef struct
{
SElemType *top;
SElemType *base;
int stacksize;
} SqStack;
Status InitStack(SqStack *s)
{
s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!s->base) exit(OVERFLOW);
s->top = s->base;
s->stacksize = STACK_INIT_SIZE;
return OK;
}
Status Push(SqStack *s, SElemType e)
{
if (s->top - s->base == s->stacksize)
{
s->base = (SElemType *)realloc(s->base, (s->stacksize + STACKINCREAMENT) * sizeof(SElemType));
if (!s->base) exit(OVERFLOW);
s->top = s->base + s->stacksize;
s->stacksize += STACKINCREAMENT;
}
s->top++;
*(s->top) = e;
return OK;
}
Status Pop(SqStack *s, SElemType *e)
{
if (s->top == s->base) exit(OVERFLOW);
*e = *(s->top);
s->top--;
return OK;
}
Status Empty(SqStack s)
{
if (s.top - s.base == )
return OK;
else
return ERROR;
}
int main()
{
SqStack OPND; //OPTR是运算符 OPND是运算数
char c, num1, num2;
InitStack(&OPND);
while((c = getchar()) != '\n')
{
switch(c)
{
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
Push(&OPND, c - '');
break;
case '+':
Pop(&OPND, &num2);
Pop(&OPND, &num1);
Push(&OPND, num1 + num2);
break;
case '-':
Pop(&OPND, &num2);
Pop(&OPND, &num1);
Push(&OPND, num1 - num2);
break;
case '*':
Pop(&OPND, &num2);
Pop(&OPND, &num1);
Push(&OPND, num1 * num2);
break;
case '/':
Pop(&OPND, &num2);
Pop(&OPND, &num1);
Push(&OPND, num1 / num2);
break;
default:
break;
}
}
while(!Empty(OPND))
{
Pop(&OPND, &c);
printf("%d ", c);
}
return OK;
}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
计算器(中缀表示法)
运算符优先级:

| 
 
  | 
 +  | 
 -  | 
 *  | 
 /  | 
 (  | 
 )  | 
 #  | 
| 
 +  | 
 >  | 
 >  | 
 <  | 
 <  | 
 <  | 
 >  | 
 >  | 
| 
 -  | 
 >  | 
 >  | 
 <  | 
 <  | 
 <  | 
 >  | 
 >  | 
| 
 *  | 
 >  | 
 >  | 
 >  | 
 >  | 
 <  | 
 >  | 
 >  | 
| 
 /  | 
 >  | 
 >  | 
 >  | 
 >  | 
 <  | 
 >  | 
 >  | 
| 
 (  | 
 <  | 
 <  | 
 <  | 
 <  | 
 <  | 
 =  | 
 0  | 
| 
 )  | 
 >  | 
 >  | 
 >  | 
 >  | 
 0  | 
 >  | 
 >  | 
| 
 #  | 
 <  | 
 <  | 
 <  | 
 <  | 
 <  | 
 0  | 
 =  | 
执行过程:
在计算 #4+3*(5-10)/5# 时栈中的执行过程如下
| 
 步骤  | 
 输入字符  | 
 执行操作  | 
 OPTR  | 
 OPND  | 
| 
 1  | 
 #  | 
 Push(#)  | 
 #  | 
|
| 
 2  | 
 4  | 
 Push(4)  | 
 #  | 
 4  | 
| 
 3  | 
 +  | 
 '#'<'+',Push(+)  | 
 # +  | 
 4  | 
| 
 4  | 
 3  | 
 Push(3)  | 
 # +  | 
 4 3  | 
| 
 5  | 
 *  | 
 '+'<'*',Push(*)  | 
 # + *  | 
 4 3  | 
| 
 6  | 
 (  | 
 '*'<'(',Push(()  | 
 # + * (  | 
 4 3  | 
| 
 7  | 
 5  | 
 Push(5)  | 
 # + * (  | 
 4 3 5  | 
| 
 8  | 
 -  | 
 '('<'-',Push(-)  | 
 # + * ( -  | 
 4 3 5  | 
| 
 9  | 
 10  | 
 Push(10)  | 
 # + * ( -  | 
 4 3 5 10  | 
| 
 10  | 
 )  | 
 '-'>')',计算并压入结果  | 
 # + * (  | 
 4 3 -5  | 
| 
 11  | 
 '('=')',脱括号  | 
 # + *  | 
 4 3 -5  | 
|
| 
 12  | 
 /  | 
 '*'>'/'计算并压入结果  | 
 # +  | 
 4 -15  | 
| 
 13  | 
 '+'<'/',Push(/)  | 
 # + /  | 
 4 -15  | 
|
| 
 14  | 
 5  | 
 Push(5)  | 
 # + /  | 
 4 -15 5  | 
| 
 15  | 
 #  | 
 '/'>'#',计算并压入结果  | 
 # +  | 
 4 -3  | 
| 
 16  | 
 '+'>'#',计算并压入结果  | 
 #  | 
 1  | 
|
| 
 17  | 
 '#'='#',脱括号  | 
 1  | 
伪代码:
初始化运算符栈;压入#;
初始化运算数栈;获取输入;
while 获取输入不为#或栈顶不为#
if 输入的是数字
压入运算数栈
获取输入
if 新输入的也是数字
十位数百位数运算
end if
else
switch 运算符栈顶与当前输入优先级比较

压入运算符栈
获得输入

弹出运算符栈顶(或#
获得输入

弹出运算符栈顶
弹出两个运算数
计算并将结果压入运算数栈
//此时不获取新输入,该循环输入的运算符作为c重新进入循环
end if
end while
输出运算数栈中剩的运算数
实现代码:
/* 只能运算-128~127之间的结果 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define OK 1
#define ERROR 0
#define SPILL -2 //math.h中已有OVERFLOW,则改用SPILL
#define STACK_INIT_SIZE 100
#define STACKINCREAMENT 10
typedef char SElemType;
typedef int Status;
typedef struct
{
SElemType *top;
SElemType *base;
int stacksize;
} SqStack;
Status InitStack(SqStack *s)
{
s->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!s->base)
exit(SPILL);
s->top = s->base;
s->stacksize = STACK_INIT_SIZE;
return OK;
}
Status EmptyStack(SqStack s)
{
if (s.top - s.base == )
return OK;
else
return ERROR;
}
Status Push(SqStack *s, SElemType e)
{
if (s->top - s->base == s->stacksize)
{
s->base = (SElemType *)realloc(s->base, (s->stacksize + STACKINCREAMENT) * sizeof(SElemType));
if (!s->base)
exit(SPILL);
s->top = s->base + s->stacksize;
s->stacksize += STACKINCREAMENT;
}
s->top ++;
*(s->top) = e;
return OK;
}
Status Pop(SqStack *s, SElemType *e)
{
if (s->top == s->base)
exit(SPILL);
*e = *(s->top);
s->top--;
return OK;
}
SElemType GetTop(SqStack s)
{
return *(s.top);
// *e = *(s.top);
// return OK;
}
/* 判断如果是数字则返回OK,运算符返回ERROR,非法输入则退出 */
Status InputJudge(SElemType c)
{
switch(c)
{
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
case '':
return OK;
break;
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '#':
return ERROR;
break;
default:
exit(SPILL);
break;
}
}
/* 当前输入的运算符和前一个运算符比较优先级 */
SElemType PriorityJudge(SElemType optr1, SElemType optr2)
{
int i, j;
char priorityTable[][] =
{
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '<', '<', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'>', '>', '>', '>', '<', '>', '>'},
{'<', '<', '<', '<', '<', '=', ''},
{'>', '>', '>', '>', '', '>', '>'},
{'<', '<', '<', '<', '<', '', '='}
};
switch(optr1)
{
case '+':
i = ;
break;
case '-':
i = ;
break;
case '*':
i = ;
break;
case '/':
i = ;
break;
case '(':
i = ;
break;
case ')':
i = ;
break;
case '#':
i = ;
break;
}
switch(optr2)
{
case '+':
j = ;
break;
case '-':
j = ;
break;
case '*':
j = ;
break;
case '/':
j = ;
break;
case '(':
j = ;
break;
case ')':
j = ;
break;
case '#':
j = ;
break;
}
return priorityTable[i][j];
}
/* 四则运算 */
SElemType Calc(SElemType optr, SElemType num1, SElemType num2)
{
switch(optr)
{
case '+':
return (num1 + num2);
break;
case '-':
return (num1 - num2);
break;
case '*':
return (num1 * num2);
break;
case '/':
return (num1 / num2);
break;
}
}
int main()
{
char c, optr, num1, num2, temp;
SqStack OPND, OPTR;
InitStack(&OPTR);
Push(&OPTR, '#');
InitStack(&OPND);
c = getchar();
while(c != '#' || GetTop(OPTR) != '#')
// while(!EmptyStack(OPTR))
//严蔚敏老师书上的算法是判断输入非#或栈顶非#时循环,个人认为判断运算符栈不为空也可以,当初始化时压入的#闭合,结束运算
{
if (InputJudge(c))
{
Push(&OPND, c - '');
c = getchar();
/* 当连续输入数字时,计算十位数和百位数 */
while(InputJudge(c))
{
int i = ;
Pop(&OPND, &temp);
Push(&OPND, temp * pow(, i) + (c - ''));
i++;
c = getchar();
}
}
else
switch(PriorityJudge(GetTop(OPTR), c))
{
case '<':
Push(&OPTR, c);
c = getchar();
break;
case '=':
Pop(&OPTR, &c);
c = getchar();
break;
case '>':
Pop(&OPTR, &optr);
Pop(&OPND, &num2);
Pop(&OPND, &num1);
Push(&OPND, Calc(optr, num1, num2));
break;
}
}
while(!EmptyStack(OPND))
{
Pop(&OPND, &c);
printf("%d\n", c);
}
return OK;
}
C语言 | 计算器实现(中缀表示法/后缀表示法)的更多相关文章
- .net表达式计算器(中缀表达式转后缀表达式,支持20多个数学函数,支持函数嵌套)
		
最近在网上查了一下表达工计算器的类库,发现Java版本的有一个比较成熟的叫W3EVal,好像是一个IBM工程师写的,.net就很少了(可能是我了解不够多),但投机取巧的实现思路有很多,比如: (1)将 ...
 - 3-06. 表达式转换(25)(中缀表达式转后缀表达式ZJU_PAT)
		
题目链接:http://pat.zju.edu.cn/contests/ds/3-06 算术表达式有前缀表示法.中缀表示法和后缀表示法等形式. 日常使用的算术表达式是採用中缀表示法,即二元运算符位于两 ...
 - 栈的应用1——超级计算器(中缀与后缀表达式)C语言
		
这里要学的程序主要用来实现一个功能——输入表达式输出结果,也就是一个计算器.效果如下: 这个程序主要有两个步骤:1.把中缀表达式转换为后缀表达式:2.计算后缀表达式的结果. 首先先明白几个问题: 1. ...
 - c语言,中缀表达式转后缀表达式并计算
		
//c语言中缀表达式计算 #include <stdio.h> #include <stdlib.h> #include <string.h> #include & ...
 - 栈的简单应用之中缀表达式转后缀表达式(C语言实现逆波兰式)
		
一.前言 普通人在书写计算式时会选择中缀表达式,这样符合人脑的认知习惯.可计算机处理时后缀表达式才能使处理速度更快,其原因是利用堆栈结构减少计算机内存访问.同时它也是一个很好锻炼栈这个数据结构的应 ...
 - 数据结构之栈—强大的四则复杂运算计算器(超过windows自带的科学计算器)【中缀转后缀表达式】
		
比windows自带计算器还强的四则复杂运算计算器! 实测随机打出两组复杂算式:-7.5 * 6 / ( -2 + ( -6.5 - -5.22 ) )与7.5+-3*8/(7+2) windows ...
 - RPN-逆波兰计算器-中缀表达式转后缀表达式-javascript
		
1.利用栈(Stack)来存储操作数和操作符: 2.包含中缀表达式转后缀表达式的函数,这个是难点,也是关键点: 2.1.将输入字符串转为数组: 2.2.对转换来的字符进行遍历:创建一个数组,用来给存储 ...
 - hdu-1237 简单计算器---中缀表达式转后缀表达式
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1237 题目大意: 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值. 思路 ...
 - C语言- 基础数据结构和算法 - 09 栈的应用_中缀表达式转后缀表达式20220611
		
09 栈的应用_中缀表达式转后缀表达式20220611 听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/ ...
 
随机推荐
- 手一抖误删了根目录 /usr 之后的挽救过程
			
一切悲剧来源于写的Shell没有好好检查,执行后把开发机的根目录 /usr 目录给删除了,而且是root执行,众所周知,/usr目录里有大量的应用层程序,删除之后导致大量命令无法使用,如 ssh / ...
 - Linux 设备驱动--- Poll 方法 --- Select【转】
			
转自:http://blog.csdn.net/yikai2009/article/details/8653842 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] Sele ...
 - 基于UDT connect连接通信以及文件传输--服务端
			
网上与UDT相关的资料不多,与UDT相关的源码例子更少.最近在接触UDT,也是因为缺少相关的资料,导致学习起来甚感痛苦.下面将我自己这两天弄出来的代码贴出来,希望对在寻找相关资料的童鞋有一定的帮助.与 ...
 - Simditor 富文本编辑器
			
Simditor 是团队协作工具 Tower 使用的富文本编辑器. 相比传统的编辑器它的特点是: 功能精简,加载快速 输出格式化的标准 HTML 每一个功能都有非常优秀的使用体验 兼容的浏览器:IE1 ...
 - 考勤的lua脚本
			
ngx.header.content_type = "text/plain;charset=utf-8" local cjson = require "cjson&quo ...
 - Mysql 通用二进制包安装
			
通用二进制包安装 注意:这里有严格的平台问题: 使用时:centos5.5版本 (类似Windows下的绿色包) 下载(mirrors.sohu.com/mysql) 直接使用tar 解压到指 ...
 - sort equal 确保记录按照 input顺序来
			
Usually you have a requirement of removing the duplicate records from a file using SORT with the opt ...
 - bzoj 2843: 极地旅行社
			
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1077 Solved: 645[Submit][Status][Discuss] Descripti ...
 - yum安装openresty
			
在群里看到春哥发的,先记录下来.一切都以官网为准,以后安装部署生态会越来越完善的. OpenResty 官方现在开始维护自己的打包虚机集合了,新的 linux 包仓库正在陆续登陆 openresty. ...
 - WPF--TextBox的验证
			
WPF--TextBox的验证
 
			
		