题前需要了解的:中缀、后缀表达式是什么?(不知道你们知不知道,反正我当时不知道,搜的百度)

基本思路:先把输入的中缀表达式→后缀表达式→进行计算得出结果

栈:”先进先出,先进后出“!

  1. 中缀转后缀(先把转换后的后缀表达式存入字符数组):从左至右依次读取,遇到运算数存入字符数组,遇到运算符压入栈,继续读取–如果遇到的运算符优先级比栈顶的运算符优先级或者相等(比如“+与+或-” ----- “* 与 或/”------“/与/或”),则先将栈中的运算符输送至字符数组(如果栈中有“(”,则只输出到左括号就停止输出,不输出左括号),继续读取–如果遇到运算符优先级比栈顶运算符高的则入栈成为新的栈顶运算符,继续读取----如果遇到“)”,则将栈元素输出至字符数组,直至输出至”(“停止(在后缀表达式中没有括号,所以括号不输出入字符数组),直至读取完毕,然后将栈中剩余的运算符输出至字符数组。完毕!(注意:在遇到右括号”)“后就要将”(“左括号从栈中删除了,因为为防止将括号输出至字符数组)。

  2. 后缀表达式求值:从左至右读取,遇到运算数则将其存入栈中,遇到运算符(比如”/“)则将栈顶元素的前一个运算数(比如temp1)与栈顶元素(比如temp2)出栈(–注意–)并进行运算,temp1/temp2,并将其最终结果重新压入栈中成为新的栈顶元素,直至得出最终结果。


上代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100
typedef float Num;//为防止以后变换操作数类型需要
typedef struct
{
Num data[MAX];
int top;
}StackNum;//运算数栈
typedef struct
{
char data[MAX];
int top;
}StackChar;//运算符栈
//------函数声明---------
void InitNum(StackNum *p);//运算数栈初始化
void PushNum(StackNum *p, Num e);//运算数压栈
void PopNum(StackNum *p, Num *e);//运算数出栈
Num GetNum(StackNum p);//取栈顶元素
//-----------------------
void InitChar(StackChar *p);//运算符栈初始化
void PushChar(StackChar *p, char e);//运算符压栈
void PopChar(StackChar *p, char *e);//运算符出栈
//-----------------------
void Fun(StackNum *p, char e);//计算并压入运算数栈
//-----------------------
void main()
{
int i;//循环变量
Num temp;//存放一个临时转换数
char str[MAX], ch;//存放中缀表达式原式,临时运算符
//-----------
StackNum n1;
StackChar c1;
InitNum(&n1);
InitChar(&c1);
//------------ for (;;)
{
printf("请输入中缀表达式:");
gets(str);
/*
注意字符串输入函数与scanf("%s",str) 的区别,scanf遇到空白字符,
包括空格,制表符,换行符时均会停止输入,所以不可取,而gets功能为读入一行,
并将换行符转换为字符串结束符。
*/
for (i = 0; str[i] != '\0'; i++)//读完整字符串-----字符串结束标志'\0'
{
if (str[i] >= '0'&&str[i] <= '9')//分岔点一:----------------------------------------------------------------如果为数字
{
temp = str[i] - '0';//-----将字符转换为数值 while (str[i + 1] != '\0')//多位数值获取
{
if (str[i + 1] >= '0'&&str[i + 1] <= '9')
{
temp = temp * 10 + str[i + 1] - '0';//------注意! i++;
}
else
break;//如果不是多位数字,则跳出多位获取循环
}
PushNum(&n1, temp);//将获取来的数值入栈
}
else if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' || str[i] == '(' || str[i] == ')')//分岔点二:-------如果为运算符
{
switch (str[i])//表达式可为:整型/字符型/枚举型-----C语言中
{
//case 后可为 整型,字符型----C语言中
case '+':
if (c1.data[c1.top - 1] != '+'&&c1.data[c1.top - 1] != '-'&&c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '+');
}
else//如果不然,则将之前的先都出栈并计算,然后再入栈
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//将优先级高的运算符先输出计算,其中括号内的优先级最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//计算,并压运算数栈 }
PushChar(&c1,'+');
}
; break;
case '-':
if (c1.data[c1.top - 1] != '+'&&c1.data[c1.top - 1] != '-'&&c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '-');
}
else//如果不然,则将之前的先都出栈并计算,然后再入栈
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//将优先级高的运算符先输出计算,其中括号内的优先级最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//计算,并压运算数栈 }
PushChar(&c1, '-');
}
; break;
case '*':
if (c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '*');
}
else//如果不然,则将之前的先都出栈并计算,然后再入栈
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//将优先级高的运算符先输出计算,其中括号内的优先级最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//计算,并压运算数栈 }
PushChar(&c1, '*');
}
; break;
case '/':
if (c1.data[c1.top - 1] != '*'&&c1.data[c1.top - 1] != '/')
{
PushChar(&c1, '/');
}
else//如果不然,则将之前的先都出栈并计算,然后再入栈
{
while (c1.top > 0 && c1.data[c1.top - 1] != '(')//将优先级高的运算符先输出计算,其中括号内的优先级最高
{
PopChar(&c1, &ch);
Fun(&n1, ch);//计算,并压运算数栈 }
PushChar(&c1, '/');
}
; break;
case '(': PushChar(&c1, '('); ; break;
case ')'://并没有将'('压入栈中,只是当作一种出栈信号
while (c1.data[c1.top - 1] != '(')
{
PopChar(&c1, &ch);
Fun(&n1, ch);//计算,并压运算数栈
}
PopChar(&c1, &ch);//将'('也出栈,但并不计算
; break;
} }
}
while (c1.top > 0)//将剩余的运算符出栈并计算
{
PopChar(&c1, &ch);
Fun(&n1, ch);
}
printf("\t\t%s=%.2f", str, GetNum(n1));
printf("\n");
system("pause");
} }
void InitNum(StackNum *p)
{
p->top = 0;
}
void InitChar(StackChar *p)
{
p->top = 0;
}
void PushNum(StackNum *p, Num e)
{
if (p->top == MAX)
printf("运算数栈满!\n");
else
{
p->data[p->top] = e;
p->top++;
}
}
void PushChar(StackChar *p, char e)
{
if (p->top == MAX)
printf("运算符栈满!\n");
else
{
p->data[p->top] = e;
p->top++;
}
}
void PopNum(StackNum *p, Num *e)
{
if (p->top == 0)
printf("运算数栈空!\n");
else
{
p->top--;
*e = p->data[p->top];
}
}
void PopChar(StackChar *p, char *e)
{
if (p->top == 0)
printf("运算符栈空!\n");
else
{
p->top--;
*e = p->data[p->top];
}
}
void Fun(StackNum *p, char e)
{
Num temp1, temp2;//存放两个临时操作数
PopNum(p, &temp2);
PopNum(p, &temp1);
switch (e)
{
case '+':PushNum(p, temp1 + temp2); break;
case '-':PushNum(p, temp1 - temp2); break;
case '*':PushNum(p, temp1*temp2); break;
case '/':PushNum(p, temp1 / temp2); break; }
}
Num GetNum(StackNum p)
{
return p.data[p.top - 1];
}

因为我也是个小菜鸟,所以本次也全当作笔记总结的文章,我又找了两篇我参考的大佬的文章,如下:

原文:https://blog.csdn.net/myCsdn_Xm/article/details/80861183

后缀表达式的求值(c语言)

题目描述

为了便于处理表达式,常常将普通表达式(称为中缀表示)转换为后缀{运算符在后,如X/Y写为XY/表达式。在这样的表示中可以不用括号即可确定求值的顺序,如:(P+Q)(R-S) → PQ+RS-。后缀表达式的处理过程如下:扫描后缀表达式,凡遇操作数则将之压进堆栈,遇运算符则从堆栈中弹出两个操作数进行该运算,将运算结果压栈,然后继续扫描,直到后缀表达式被扫描完毕为止,此时栈底元素即为该后缀表达式的值。

输入

输入一行表示后缀表达式,数与数之间一定有空格隔开(可能不只一个空格),最后输入@表示输入结束。

数据保证每一步的计算结果均为不超过100000的整数。

输出

输出一个整数,表示该表达式的值.

样例输入

14 3 20 5 / *8 - + @

样例输出

18

#include<stdio.h>

typedef struct STRACK                                              //定义结构体
{
double a[100];
int top;
} STRACK; int main()
{
double totle=0,e=0;
char s[100];
int i; STRACK L;
L.top=-1;
gets(s);
for(i=0; s[i]!='@'; i++)
{
if(s[i]<='9'&&s[i]>='0')
{
L.top++;
int temp=s[i]-'0';
int k=i+1;
while(s[k]!='@') //利用while循环得到由多位由字符组成的数值
{
if(s[k]<='9'&&s[k]>='0')
{
temp=10*temp+(s[k]-'0');
i++;
k++;
}
else break;
}
L.a[L.top]=temp;
}
else if(s[i]=='+'||s[i]=='-'||s[i]=='*'||s[i]=='/') //遇到运算符进行计算
{
switch(s[i])
{
case '+':
e=L.a[L.top-1]+L.a[L.top];
break;
case '-':
e=L.a[L.top-1]-L.a[L.top];
break;
case '*':
e=L.a[L.top-1]*L.a[L.top];
break;
case '/':
e=L.a[L.top-1]/L.a[L.top];
break;
}
L.a[L.top-1]=e; //往前一位存储
L.a[L.top]=0;
L.top--;
}
}
printf("%.0lf",L.a[L.top]); //输出最后结果
return 0;
}

原文:https://blog.csdn.net/hanmiaobei7428/article/details/82049881

中缀表达式的求值问题

表达式的求值问题(堆栈)

0. 解决目标

将形如2*(9+6/3-5)+4表达式求值的思想

  1. 后缀表达式的求值

形如这里写图片描述的表达式如何求值?

(翻译成中缀表达式为:6/2-3+4*2,我们不进行中缀表达式的翻译操作,只是为了方便理解中间的过程)

从左向右“扫描”,逐个处理运算数和运算符号

遇到运算数怎么办?如何“记住”目前还不未参与运算的数?

遇到运算符号怎么办?对应的运算数是什么?



下图是一种解决办法。



这里使用一种结构,由于长得像先称之为“槽”,这种槽有什么特点?

1.只能存放数字

2.存放的数字只能后面进来的先出

这里有个问题,如果是符号怎么办呢?

我们提供一种解决办法,如果遇到符号,则将槽最顶部的数字与前一个数字从槽中拿出,进行操作,操作为:

1.前一个数字 运算符 槽最顶部的数字

2.并讲运算结果 再放入槽中

3.直至所有东西都按从左到右的顺序 尝试进入槽中,便得到结果。

这种能够解决后缀表达式的求值问题的结构——“槽”,就是堆栈。它是一种线性存储结构,后入先出。

我们用堆栈解决了后缀表达式的求值问题,那么问题来了,如何将中缀表达式转换成后缀表达式呢?

##2. 中缀化后缀

目标:将形如2*(6/3+4)-5的中缀表达式化成 2 6 3 / 4 + * 5 -的后缀表达式

带括号的表达式看起来比较复杂,我们先看没有括号的转换。

小目标:将形如2+9/3-5的中缀表达式化成2 9 3 / + 5 - 的后缀表达式

构造一种堆栈,只能存放符号,同样遵循后入先出的原则。

有两个问题

1.遇到数字怎么办?

2.堆栈中的符号怎么处理?

第一个问题很简单,输出即可,因为我们只需要求表达式,并不需要同时计算。

第二个问题,因为符号有优先级,当将符号放入堆栈时,比较其与前一个符号的优先级,若低于,则先输出前一个运算符。这个也很好理解,高优先级的运算先进行。

解决过程如下图所示。



那如果带括号要怎么解决呢?问题有:

1.括号也算一种符号,但括号不参与运算,

2.括号提供一种优先级,括号里面的运算优先级最高

第一个问题,我们在后缀表达式转换成值的时候是直接进行操作的,利用顺序已经将括号的功能包括进去,但只是不显示括号而已。具体解决是在一对括号齐全时,将其中的运算符输出。

第二个问题,我么将括号放入堆栈之前认为其优先级最高,在放入堆栈之后,将其认为优先级最低,即只进行括号里面的优先级比较(忽略括号)。

解决过程如下图。



总结中缀表达式转化成后缀表达式的方法如下:



按照 步骤2->1->0 完成目标


学习自《数据结构:陈越》之线性结构


呼,终于把最近看的,学的,总结起来了。。。

我如果有什么地方弄得不对的,看到的道友可以在下方评论说出来,或者私信我。

学习使我们快乐~

C语言中缀表达式求值(综合)的更多相关文章

  1. 刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决

    1. 表达式的种类 如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题,作为栈的应用事例,下面介绍表达式的求值过程. 任何一个表达式都是由操作数(亦称运算对象).操作符(亦称运算 ...

  2. C语言实现表达式求值,支持+、-、*、/四则运算,并且支持多级括号,自定义了栈的操作。

    以下是代码的实现使用gcc已经成功运行了,下面是效果图 #include <stdio.h> #include <stdlib.h> #define OPT_ADD 43 /* ...

  3. 第四章 栈与队列(c4)栈应用:中缀表达式求值

  4. FZU2215 Simple Polynomial Problem(中缀表达求值)

    比赛时没做出这题太可惜了. 赛后才反应过来这就是个中缀表达式求值,数字栈存的不是数字而是多项式. 而且,中缀表达式求值很水的,几行就可以搞定. #include<cstdio> #incl ...

  5. C++之字符串表达式求值

    关于字符串表达式求值,应该是程序猿们机试或者面试时候常见问题之一,昨天参加国内某IT的机试,压轴便为此题,今天抽空对其进行了研究. 算术表达式中最常见的表示法形式有 中缀.前缀和 后缀表示法.中缀表示 ...

  6. 数据结构课程设计四则运算表达式求值(C语言版)

    本系统为四则运算表达式求值系统,用于带小括号的一定范围内正负数的四则运算标准(中缀)表达式的求值.注意事项:    1.请保证输入的四则表达式的合法性.输入的中缀表达式中只能含有英文符号"+ ...

  7. 数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

    一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚, ...

  8. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  9. C/C++ 语言中的表达式求值(原文作者:裘宗燕)

    经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...

随机推荐

  1. NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis

    目录 概 主要内容 positional encoding 额外的细节 代码 Mildenhall B., Srinivasan P. P., Tancik M., Barron J. T., Ram ...

  2. Python猫 2021 文章小结,翻译竟比原创多!

    最近给自己放了两周的"长假",刷视频.看小说.玩游戏,就是不写文章不更新公众号. 半途而废的事情令得 2021 年的时间流逝加快,最后留下只是遗憾和不甘. 又到了新的一年,按照惯例 ...

  3. EMQX源码编译过程

    以emqx4.0.7版本为例 1.安装erlang环境 可以参考:https://www.cnblogs.com/shanfeng1000/p/11951703.html 这里需要注意一下,要按照em ...

  4. Swoole 中使用 PDO 连接池、Redis 连接池、Mysqli 连接池

    连接池使用说明 所有连接池的实现均基于 ConnectionPool 原始连接池: 连接池的底层原理是基于 Channel 的自动调度: 开发者需要自己保证归还的连接是可重用的: 若连接不可重用,需要 ...

  5. yum 下载安装包以及依赖包

    有时候我在用yum安装软件,依赖包比较多,还受网速的影响.所以我们可以将安装包以及依赖包下载到本地安装,这样会快捷很多. yum 提供了这种功能 yum -y install yum-utils 下载 ...

  6. BOM 点击触发 倒计时发送验证码案例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. python自动化测试框架的unittest与pytest前后置条件的区别

    前言: 笔者先试有用过unittest的前后置条件和pytest的前后置条件,觉得pytest的前后置条件比unittest的要简洁.方便很多.不过在使用unittest的前后置条件时,已经觉得在和每 ...

  8. elasticsearch设置密码

    ELK - X-Pack设置用户密码 enable X-Pack security vi elasticsearch.yml #首先开启x-pack插件 xpack.security.enabled: ...

  9. ModelForm has no model class specified

    未指定模型类,错误发生在把model拼写错误 来自为知笔记(Wiz)

  10. Java安全之Spring内存马

    Java安全之Spring内存马 基础知识 Bean bean 是 Spring 框架的一个核心概念,它是构成应用程序的主干,并且是由 Spring IoC 容器负责实例化.配置.组装和管理的对象. ...