【C++】同样是讲解逆波兰式,为何这篇就图文并茂,通俗易懂呢?
时间:2022-07-23
本文章向大家介绍【C++】同样是讲解逆波兰式,为何这篇就图文并茂,通俗易懂呢?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
什么是波兰表达式
人类最熟悉的一种表达式1+2,(1+2)*3,3+4 *2+4等等都是中缀表示法。对于人们来说,也是最直观的一种求值方式,先算括号里的, 然后算乘除,最后算加减,但是,计算机处理中缀表达式却并不方便,因为没有一种简单的数据结构可以方便从一个表达式中间抽出 一部分算完结果,再放进去,然后继续后面的计算(链表也许可以,但是,代价也是不菲)。
因此,1920年,波兰科学家扬·武卡谢维奇(Jan ukasiewicz)发明了一种不需要括号的计算表达式的表示法将操作符号写在操作数之前,也就是前缀表达式,即波兰式(Polish Notation, PN)。
中缀表达式转逆波兰表达式
这里使用栗子:(1 + 2 * (4 - 3) + 6/2)
算法伪代码(如果不清楚流程的话,务必要先看一下)
输入:中缀表达式串
输出:后缀表达式串
PROCESS BEGIN:
1.从左往右扫描中缀表达式串s,对于每一个操作数或操作符,执行以下操作;
2.IF (扫描到的s[i]是操作数DATA)
将s[i]添加到输出队列中;
3.IF (扫描到的s[i]是开括号'(')
将s[i]压栈;
4.WHILE (扫描到的s[i]是操作符OP)
IF (栈为空 或 栈顶为'(' 或 扫描到的操作符优先级比栈顶操作符高)
将s[i]压栈;
BREAK;
ELSE
出栈至输出队列中
5.IF (扫描到的s[i]是闭括号')')
栈中运算符逐个出栈并输出,直到遇到开括号'(';
开括号'('出栈并丢弃;
6.返回第1.步
7.WHILE (扫描结束而栈中还有操作符)
操作符出栈并加到输出队列中
PROCESS END
所以将上面的栗子放进去走一圈出来会怎样?
in>>(1 + 2 * (4 - 3) + 6/2) out<<1 2 4 3 -*+ 6 2 / +
了解流程之后,我们来看个表:对于上面的栗子的转换
后缀表达式运算流程
逆波兰表达式的计算就比较简单了。以上面结果中的队列为输入,同时再准备一个栈用于运算。具体流程如下:
- 将队列中的数据依次出队,然后压栈;
- 在出队的过程中如果遇到运算符,则从栈中弹出2个运算数,分别作为右运算数和左运算数,进行运算;
- 将步骤2的运算结果入栈;
- 跳入步骤1,继续进行出队操作。
对上面栗子进行流程化:
①
②
③
放码过去
这是一个多项式计算器的代码,注释我就没放。
#ifndef _STACK_H_
#define _STACK_H_
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
typedef struct node
{
int data;
struct node *next;
}Node;
typedef struct stack
{
Node *top;
}Stack;
void Init(Stack *s);
int Empty(Stack *s);
void Push(Stack *s, int data);
void Pop(Stack *s);
int GetTop(Stack *s);
#endif
#include "stack.h"
void Init(Stack *s)
{
if (NULL == s)
return;
s->top = NULL;
}
int Empty(Stack *s)
{
if (NULL == s)
return 0;
if (NULL == s->top)
return 1;
return 0;
}
void Push(Stack *s,int data)
{
if (NULL == s)
return;
Node *node = (Node *)malloc(sizeof(Node)/sizeof(char));
if (NULL == node)
return;
node->data = data;
node->next = s->top;
s->top = node;
}
void Pop(Stack *s)
{
if (NULL == s)
return;
if (Empty(s) == 1)
return;
Node *tmp = s->top;
s->top = tmp->next;
free(tmp);
}
int GetTop(Stack *s)
{
if (NULL == s)
return;
if (Empty(s) == 1)
{
printf ("无栈顶元素n");
exit(-1);
}
return s->top->data;
}
#include <stdio.h>
#include "stack.h"
#include <string.h>
int Ope_judge(Stack *s_ope,int ope)
{
if(Empty(s_ope))
return 1;
int top = GetTop(s_ope);
switch(top)
{
case '+':
case '-':
if(ope == '*' || ope == '/' || ope == '(')
return 1;
break;
case '*':
case '/':
if( ope == '(')
return 1;
break;
case '(':
if(ope == ')')
{
Pop(s_ope);
}
return 1;
default :
break;
}
return 0;
}
void Calc(Stack *s_ope,Stack *s_num)
{
int num1 = GetTop(s_num);
Pop(s_num);
int num2 = GetTop(s_num);
Pop(s_num);
int ope = GetTop(s_ope);
Pop(s_ope);
int res;
switch(ope)
{
case '+':
res = num2 + num1;
break;
case '-':
res = num2 - num1;
break;
case '*':
res = num2 * num1;
break;
case '/':
res = num2 / num1;
break;
default:
break;
}
Push(s_num,res);
}
void Ope_deal(Stack *s_ope,Stack *s_num,int ope)
{
if(Ope_judge(s_ope,ope) == 1)
{
Push(s_ope,ope);
}
else
{
while(Ope_judge(s_ope,ope) == 0)
{
Calc(s_ope,s_num);
}
if(ope != ')')
Push(s_ope,ope);
}
}
int main()
{
char buf[100];
fgets(buf,100,stdin);
buf[strlen(buf)-1] = ' ';
Stack s_num;
Stack s_ope;
Init (&s_num);
Init (&s_ope);
char *p = buf;
while(*p)
{
if(*p >= '0' && *p <= '9')
{
int num = 0;
while(*p >= '0' && *p <= '9')
{
num = num *10 + *p - '0';
p++;
}
Push(&s_num , num);
continue;
}
Ope_deal(&s_ope,&s_num,*p);
p++;
}
while(!Empty(&s_ope))
{
Calc(&s_ope,&s_num);
}
int res = GetTop(&s_num);
printf ("计算结果为:%dn", res);
return 0;
}
- mysql执行计划看是否最优
- 通过IP定位区域的SQL优化思路(r10笔记第10天)
- Java基础-day06-知识点回顾与练习
- 【Go 语言社区】Golang语言的多核并行化例子
- 一条SQL语句的执行计划变化探究(r10笔记第9天)
- 【Go 语言社区】Web 通信 之 长连接、长轮询(long polling)--转
- Dubbo入门-协议;注册中心
- Oracle 12c PDB浅析(二)(r8笔记第29天)
- 【Go 语言社区】在 Go 语言中,如何正确的使用并发
- Data Guard高级玩法:通过闪回恢复failover备库 (r10笔记第7天)
- ajax跨域问题-web开发必会
- 在线重定义的补充测试(r10笔记第26天)
- 聊聊Data Guard中的DG Broker(r10笔记第24天)
- stuts2返回json数据简单实现
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 10X bam文件按barcode分割
- 格拉姆-施密特正交化说明
- flow.ci - 简单强大的开源 CI/CD 工具
- golang切片
- CSRF跨站请求伪造——原理及复现
- 【Spark】常见的编译错误
- 聊聊dubbo-go的randomLoadBalance
- CentOS 6 安装 Chrome最简单的方法
- Mysql事物和锁
- PyTorch7:torch.nn.init
- Puppeteer 入门与实战
- 【DB笔试面试854】在Oracle中,删除数据库的方式有哪几种?
- 方差齐性检验
- Windows WSL2 htop打开黑屏的问题解决
- 【DB笔试面试855】在Oracle中,简单说说PSU升级的过程