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/ ...
随机推荐
- VS2013 更改MFC标题栏图标和生成的执行文件图标
创建一个新工程,可以什么都不加.打开.rc, 创建或打开Icon资源(以下都以Icon为例). 单击工程窗口的资源视图标签,选中资源ID为IDR_MAINFRAME图标资源,然后按Delet ...
- 非常好!!!Linux源代码阅读——中断【转】
Linux源代码阅读——中断 转自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/2_int.html 目录 为什么要有中断 中断的作用 中断的处 ...
- Java错误随手记
一.Eclipse启动时提示: An internal error occurred during: "Initializing Java Tooling" 1.关闭Eclipse ...
- python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决【转载】
原文转自:http://bbs.chinaunix.net/thread-4154743-1-1.html python3中用HTMLTestRunner.py报ImportError: No mod ...
- vagrant virtualbox VM inaccessible解决办法
vagrant无法访问的提示:Please open VirtualBox and clear out your inaccessible virtual machines or find a way ...
- jquery mloading
在执行jQuery的ajax时,有的时候请求回来会有较长时间,这个时候,如果什么都没有显示,用户会觉得网站卡住了,所以这个时候,来个mloading会使用户体验更好些. 使用方法很简单 将jquery ...
- R 语言词云wordcloud
来源:http://blog.chinaunix.net/uid-25135004-id-4311592.html wordcloud函数--用于绘制词云图 用法: wordcloud(words,f ...
- ORA-17003. Invalid column index
sql里面有? 希望输入有参数 java程序里面没有给入参数
- Strobogrammatic Number -- LeetCode
A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside ...
- POJ 2100:Graveyard Design(Two pointers)
[题目链接] http://poj.org/problem?id=2100 [题目大意] 给出一个数,求将其拆分为几个连续的平方和的方案数 [题解] 对平方数列尺取即可. [代码] #include ...