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/ ...
随机推荐
- UVA 10519 !! Really Strange !!
//ans=2*n+(n-1)(n-2) n>=2#include <map> #include <set> #include <list> #include ...
- [Oracle] Setup DataGuard
Oracle一步步搭建DataGuard DataGuard环境: OS: SuSe 10 Primary DB: IP address:1.1.1.1 user:root passwd:****** ...
- 解决provisional headers are shown问题
前端通过ajax的get请求向后端发送数据,后端死活收不到. ajax代码如下: $.ajax({ url:"/news_list", type:"GET", ...
- pycharm配置pep8
可以使用外部工具,来检查代码是否符合pep8的风格: 1)下载 autopep8,这个简单,pip3 install pep8 2)在pychamr中配置: A)file-setting..-tool ...
- POJ 2923 【01背包+状态压缩/状压DP】
题目链接 Emma and Eric are moving to their new house they bought after returning from their honeymoon. F ...
- [BZOJ2460][BJOI2011]元素(线性基)
2460: [BeiJing2011]元素 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2195 Solved: 1119[Submit][Sta ...
- [BZOJ 2547] 玩具兵
Link: BZOJ 2547 传送门 Solution: 很容易通过解可行性的单调性想到二分答案,接下来考虑如何验证解 发现一个很奇妙的条件:步兵和骑兵的个数相同 因此交换位置时不用考虑可行性,保证 ...
- (转)Unity3D协同程序(Coroutine)
一.什么是协同程序 协同程序,即在主程序运行时同时开启另一段逻辑处理,来协同当前程序的执行.换句话说,开启协同程序就是开启一个线程. 二.协同程序的开启与终止 在Unity3D中,使用MonoBeha ...
- C++中数据对齐问题。struct、union、enum,类继承。再谈sizeof()
首先是struct,在C++中,结构体其实和class有很大的相似了.但是有一点不同的是,struct默认是public,而class中是private. 当然,struct继承等用法也是可以的. 共 ...
- UITableView的横向使用
UITableView只支持竖向显示,要实现横向的显示,需要设置tableView 和cell 的transform属性为CGAffineTransformMakeRotate(-M_PI/2) // ...