C语言学习知识后缀表达式计算

合集下载

计算后缀表达式的过程(C#)

计算后缀表达式的过程(C#)

计算后缀表达式的过程(C#)
计算后缀表达式的过程是⼀个很好玩的过程,⽽且很简单哦!这⾥呢,有个计算的技巧,就是:遇到数字直接⼊栈,遇到运算符就计算!
后缀表达式也叫逆波兰表达式,求值过程可以⽤到栈来辅助存储;
假定待求值的后缀表达式为:12 4 + 13 - 6 2 * + =
求计算出最终结果:
(1)⾸先我们看到在第⼀个运算符之前呢,有两个数字,那么我们就先把它放⼊栈中:
注:我们可以看到,下标是从下⽅开始读的,⼀定要注意哦,不要弄反了
(2)读到“+”,则弹出12和4,执⾏相加,12+4,=16,并把16放进栈中:(先弹12,再弹4,顺序不能弄错了!!)
(3)读到数字“13”,则直接把13放⼊栈内:
(4)读到运算符“-”,则弹出16和13,执⾏相减,那么16-13=3,并把3放⼊到栈中:
注:在这⾥我们可以看到,如果我们把弹出的顺序弄反了,那么得到的数字就会完全不同,那后⾯的结算也会完全不⼀样,所以,弹出的顺序不能弄反了
(5)读到数字“6”,直接⼊栈:
(6)读到数字“2”,直接⼊栈:
(7)读到运算符“*”,弹出6和2,执⾏相乘,6*2=12,并把12放⼊到栈中:
(8)读到运算符“+”,则弹出3和12,执⾏相加,3+12=15,并把15放⼊栈中:
(9)到了这⾥,我们已经把后缀表达式都已经执⾏了⼀遍,那么得到的最后结果为15,故:
12 4 + 13 - 6 2 * + = 15
这就是运算过程,是不是很简单
END。

基于栈的后缀算术表达式求值c语言

基于栈的后缀算术表达式求值c语言

基于栈的后缀算术表达式求值c语言1. 引言1.1 概述本文将讨论基于栈的后缀算术表达式求值的实现过程。

后缀算术表达式(也称为逆波兰表达式)是一种无需括号即可进行运算的表达式表示方法,它将操作符置于操作数之后。

相较于传统的中缀表达式,在计算机程序中处理后缀表达式更为高效和简洁。

1.2 文章结构文章分为五个主要部分:引言、栈的概念及原理、后缀算术表达式的定义和转换、基于栈的后缀算术表达式求值算法实现以及结论与总结。

在引言部分,我们将首先介绍本文的概述和目标,对后续内容进行简要说明。

1.3 目的通过本文,我们旨在让读者了解栈数据结构的基本概念和原理,并且掌握如何利用栈来实现对后缀算术表达式进行求值的算法。

同时,我们将介绍后缀算术表达式的定义和转换方法,并给出基于栈实现该计算方式的详细步骤与示例代码。

通过深入研究并学习这些内容,读者可以加深对栈数据结构和后缀算术表达式的理解,并且能够应用所学知识解决实际问题。

本文不仅适用于计算机科学或相关专业的学生,也适合对数据结构和算法感兴趣的读者阅读和学习。

2. 栈的概念及原理2.1 栈的定义栈是一种具有特定限制条件的线性数据结构,它具备“先进后出”(Last-In-First-Out,LIFO)的特性。

栈可以看作是一个容器,其中可以存储各种类型的数据。

与实际生活中的堆栈类似,栈只允许在其末尾进行插入和删除操作。

在栈中,最后加入的元素首先被访问和处理。

这是由于栈内元素之间的相对位置关系决定的。

插入操作称为“压栈”(Push),删除操作称为“弹栈”(Pop),而从栈顶读取元素或获取栈顶元素但不删除它称为“查看”(Peek)。

2.2 栈的基本操作推入元素:将一个元素添加到栈顶。

如果已经存在满员条件,则无法执行此操作。

弹出元素:从栈顶移除一个元素,并返回移除的值。

如果没有任何元素存在,则无法执行此操作。

查看栈顶元素:获取位于栈顶处的元素值,但不对其进行删除。

判断是否为空:检查栈是否为空。

c语言前缀后缀运算规则(一)

c语言前缀后缀运算规则(一)

c语言前缀后缀运算规则(一)C语言前缀后缀运算规则在C语言中,前缀和后缀运算符是一种对变量或表达式进行操作的方式。

它们可以应用于不同的数据类型,并具有不同的行为。

以下是关于C语言前缀和后缀运算规则的简述和示例解释:前缀运算符前缀运算符是紧跟在变量或表达式之前的运算符。

它会在使用变量之前对其进行操作,然后返回操作后的值。

1. 前缀递增运算符(++)前缀递增运算符会将变量的值加1,并返回加1后的值。

int a = 5;int b = ++a; // a先加1,然后将加1后的值赋给b// a = 6, b = 62. 前缀递减运算符(–)前缀递减运算符会将变量的值减1,并返回减1后的值。

int a = 5;int b = --a; // a先减1,然后将减1后的值赋给b// a = 4, b = 4后缀运算符后缀运算符是紧跟在变量或表达式之后的运算符。

它会先使用变量的值,然后再对其进行操作,并返回操作前的值。

1. 后缀递增运算符(++)后缀递增运算符会将变量的值加1,并返回操作前的值。

int a = 5;int b = a++; // b先被赋值为a的值,然后a加1// a = 6, b = 52. 后缀递减运算符(–)后缀递减运算符会将变量的值减1,并返回操作前的值。

int a = 5;int b = a--; // b先被赋值为a的值,然后a减1// a = 4, b = 5总结在C语言中,前缀和后缀运算符的行为有所不同。

前缀运算符会先对变量进行操作,然后返回操作后的值;而后缀运算符则是先使用变量值,然后再对其进行操作,并返回操作前的值。

需要注意的是,在同一个表达式中多次使用前缀或后缀递增(递减)运算符时,其行为是未定义的。

因此,在编写代码时要避免在同一个表达式中多次出现这些运算符。

希望本文能够对C语言前缀和后缀运算规则有一定的了解,并能在编程过程中正确使用它们。

后缀表达式求值过程

后缀表达式求值过程

后缀表达式求值过程嘿,朋友!今天咱们来唠唠后缀表达式求值这个超有趣的事儿。

你可能会想,这后缀表达式是啥呀?就像你看到一个神秘的密码,其实只要掌握了方法,求值就像解开密码锁一样简单又好玩。

我先给你说说啥是后缀表达式吧。

咱平常看到的表达式,像“3 + 4”这种中缀表达式,操作符在中间。

而后缀表达式呢,操作符在操作数的后面,就像“3 4 +”。

这看起来有点怪,可它在计算机处理起来可就方便多啦。

那怎么求值呢?咱得有个小工具,那就是栈。

栈就像一个小盒子,不过这个小盒子有点特别,先放进去的东西后拿出来,就像你往一个窄口瓶子里塞东西,先塞进去的在底下,最后才能拿出来。

比如说咱们要计算“4 5 * 6 +”这个后缀表达式的值。

我和我那聪明的小伙伴小明就开始啦。

小明负责操作栈,我来指挥。

首先看到“4”,小明就把4这个数字放到栈里。

这就像把一个小宝贝放进那个神秘的盒子里。

接着看到“5”,小明也把5放进栈里。

现在栈里就有4和5啦,就像两个小伙伴在盒子里安静地待着。

然后看到“*”这个操作符,这时候就像魔法要开始啦。

小明从栈里拿出5和4(注意哦,是先拿5,因为栈的特性),然后计算4乘以5等于20,再把20放进栈里。

哇,这就像把两个小伙伴融合成了一个超级小伙伴呢!再看到“6”,小明又把6放进栈里。

现在栈里有20和6啦。

最后看到“+”,小明又从栈里拿出6和20,计算20加6等于26,这就是最后的结果啦。

是不是感觉很神奇呢?就像一场奇妙的数学之旅。

再来看一个复杂点的例子吧。

像“3 4 + 2 * 5 -”。

我和我的另一个朋友小花来操作这个。

小花可认真啦。

先看到“3”,放进栈里,再看到“4”,也放进栈里。

看到“+”的时候,小花从栈里拿出4和3,计算3加4等于7,把7放进栈里。

这时候就像我们搭建了一个小积木塔的一部分。

接着看到“2”,放进栈里。

看到“*”的时候,小花从栈里拿出2和7,计算7乘以2等于14,再把14放进栈里。

最后看到“5”,放进栈里,看到“ - ”的时候,小花从栈里拿出5和14,计算14减5等于9。

C#算术表达式求值(后缀法),看这一篇就够了

C#算术表达式求值(后缀法),看这一篇就够了

C#算术表达式求值(后缀法),看这⼀篇就够了⼀、种类介绍算术表达式有三种:前缀表达式、中缀表达式和后缀表达式。

⼀般⽤的是中缀,⽐如1+1,前后缀就是把操作符移到前⾯和后⾯,下⾯简单介绍⼀下这三种表达式。

1、前缀表⽰法前缀表⽰法⼜叫波兰表⽰法,他的操作符置于操作数的前⾯(例:+ 1 2),是波兰数学家扬·武卡谢维奇1920年代引⼊的,⽤于简化命题逻辑。

因为我们⼀般认为操作符是在操作数中间的,所以在⽇常⽣活中⽤的不多,但在计算机科学领域占有⼀席之地。

⼀般的表⽰法对计算机来说处理很⿇烦,每个符号都要考虑优先级,还有括号这种会打乱优先级的存在,将使计算机花费⼤量的资源进⾏解析。

⽽前缀表⽰法没有优先级的概念,他是按顺序处理的。

举个例⼦:9-2*3这个式⼦,计算机需要先分析优先级,先乘后减,找到2*3,再进⾏减操作;化成前缀表⽰法就是:- 9 * 2 3,计算机可以依次读取,操作符作⽤于后⼀个操作数,遇到减就是让9减去后⾯的数,⽽跟着9的是乘,也就是说让9减去乘的结果,这对计算机来说很简单,按顺序来就⾏了。

2、中缀表⽰法这也就是我们⼀般的表⽰法,他的操作符置于操作数的中间(例:1 + 2),前⾯也说过这种⽅法不容易被计算机解析,但他符合⼈们的普遍⽤法,许多编程语⾔也就⽤这种⽅法了。

在中缀表⽰法中括号是必须有的,要不然运算顺序会乱掉。

3、后缀表⽰法后缀表⽰法⼜叫逆波兰表⽰法,他的操作符置于操作数的后⾯(例:1 2 +),他和前缀表⽰法都对计算机⽐较友好,但他很容易⽤堆栈解析,所以在计算机中⽤的很多。

他的解释过程⼀般是:操作数⼊栈;遇到操作符时,操作数出栈,求值,将结果⼊栈;当⼀遍后,栈顶就是表达式的值。

因此逆波兰表达式的求值使⽤堆栈结构很容易实现,且能很快求值。

注意:逆波兰记法并不是简单的波兰表达式的反转。

因为对于不满⾜交换律的操作符,它的操作数写法仍然是常规顺序,如,波兰记法/ 6 3的逆波兰记法是6 3 /⽽不是3 6 /;数字的数位写法也是常规顺序。

算法笔记--中缀表达式转后缀表达式后缀表达式计算

算法笔记--中缀表达式转后缀表达式后缀表达式计算

算法笔记--中缀表达式转后缀表达式后缀表达式计算中缀表达式转后缀表达式规则中缀表达式a + b*c + (d * e + f) * g,转换成后缀表达式则为a b c * + d e * f + g * +转换过程需要⽤到栈,具体过程如下:1 如果遇到操作数,我们就直接将其输出。

2 如果遇到操作符,则我们将其放⼊到栈中,遇到左括号时我们也将其放⼊栈中。

3 如果遇到⼀个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为⽌。

注意,左括号只弹出并不输出。

4 如果遇到任何其他的操作符,如+, *, (等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为⽌。

弹出完这些元素后,才将遇到的操作符压⼊到栈中。

有⼀点需要注意,只有在遇到 )的情况下我们才弹出( ,其他情况我们都不会弹出( 。

即:若操作符op的优先级⾼于栈顶操作符的优先级,则压⼊操作符栈若操作符op的优先级⼩于等于栈顶操作符的优先级,则将操作栈的操作符不断弹出到后缀表达式中,直到op的优先级⾼于栈顶操作符的优先级5 如果我们读到了输⼊的末尾,则将栈中所有元素依次弹出。

实例a +b *c + (d *e + f) * g1. ⾸先读到a,直接输出。

2. 读到“+”,将其放⼊到栈中。

3. 读到b,直接输出。

此时栈和输出的情况如下:4. 读到“*”,因为栈顶元素"+"优先级⽐" * " 低,所以将" * "直接压⼊栈中。

5. 读到c,直接输出。

此时栈和输出情况如下:6. 读到" + ",因为栈顶元素" * "的优先级⽐它⾼,所以弹出" * "并输出,同理,栈中下⼀个元素" + "优先级与读到的操作符" + "⼀样,所以也要弹出并输出。

然后再将读到的" + "压⼊栈中。

10.后缀式算术表达式

10.后缀式算术表达式

解析算术表达式[1]后缀式(逆波兰式)后缀(postfix, 也成逆波兰reverse Polish)表达式在我们的生活中并不常见,在我们日常中见到的,通常都是中缀(infix)式,例如:3.14 + 15 * (9.2 – 6.5)这是便于人类理解的表达式,之所以便于人类理解,是因为人从小便接受识别此类表达式的教育,而且这种记号方式将运算符和数字明确的分开,不会产生数字堆叠在一起的混乱情况。

但是对于计算机而言,这样的表达式并不好理解,计算机是一种线性读入信息,线性输出信息的工具,人类所通识的中缀式,对于这种规规矩矩按照顺序计算的工具而言,是不容易理解的。

你可能一眼就看出来要先算小括号里的表达式,然后算乘法,最后算加法。

而计算机直接读入的话,可能会先算3.14 + 15,这自然是荒谬的,而后缀法就为计算机计算表达式提供了一种非常有效的解决方案。

这篇文章主要的内容是介绍如何将中缀表达式转换为后缀表达式。

说了这么半天,后缀表达式又是什么样子呢?它又有什么样的优势呢?我们现在来看一组对比:后缀表达式为什么会有优势呢?因为计算机线性读入的特征,我们以第二个表达式为例,以:用后缀式,在计算机的计算过程就是:1.a2.a b3.a b c4.a b c *5.a (b * c) 计算出b * c的值记作x6.a x +7.(a + x) 计算出a + x 的值就是这样一个符合线性读入过程的运算,这样就合理的解决了运算之间优先关系的处理。

那么如何将一个中缀式装换为后缀式呢?其实算法很简单,运用之前我介绍过的“栈”就可以轻易达到这个目的,我们使用两个栈,一个是表达式栈,用来存储转换成后缀表达式的结果,一个是运算符栈,用来暂存表达式中的运算符,这个栈满足条件“从栈顶到栈底,运算符的优先级依次下降”,我们以表达式a + b * (c + d) 作为例子,来模拟一下转换的过程:1.读入数字a,存入表达式栈,紧接着读入运算符+,存入运算符栈2.读入数字b,存入表达式栈,紧接着读入运算符*,由于*比+运算优先级高,所以也可以存入运算符栈3.读入左括号(,(具有最高优先级,所以也存入运算符栈,后面的数字c存入表达式栈4.读入运算符+,存入运算符栈,然后读入数字d,存入表达式栈5.读入右括号),开始弹出运算符栈中的运算符到表达式栈,直到遇到左括号为止6.表达式已经读完了,将运算符栈中的运算符全部弹出到表达式栈,至此后缀表达式已经转换完成!总结下来,基本步骤很明确,就是以下几个步骤:(1)读入,如果是数字,就置入表达式栈,然后重复(1)。

(完整版)数学表达式计算(c语言实现)

(完整版)数学表达式计算(c语言实现)

一、设计思想计算算术表达式可以用两种方法实现:1.中缀转后缀算法此算法分两步实现:先将算术表达式转换为后缀表达式,然后对后缀表达式进行计算。

具体实现方法如下:(1)中缀转后缀需要建一个操作符栈op和一个字符数组exp,op栈存放操作符,字符数组用来存放转换以后的后缀表达式。

首先,得到用户输入的中缀表达式,将其存入str数组中。

对str数组逐个扫描,如果是数字或小数点,则直接存入exp数组中,当扫描完数值后,在后面加一个#作为分隔符。

如果是操作符,并且栈为空直接入栈,如果栈不为空,与栈顶操作符比较优先等级,若比栈顶优先级高,入栈;如果比栈顶优先级低或相等,出栈将其操作符存到exp数组中,直到栈顶元素优先等级低于扫描的操作符,则此操作符入栈;如果是左括号,直接入栈,如果是右括号,出栈存入exp数组,直到遇到左括号,左括号丢掉。

然后继续扫描下一个字符,直到遇到str中的结束符号\0,扫描结束。

结束后看op栈是否为空,若不为空,继续出栈存入exp数组中,直到栈为空。

到此在exp数组最后加结束字符\0。

我们就得到了后缀表达式。

(2)后缀表达式计算此时需要一个数值栈od来存放数值。

对exp数组进行逐个扫描,当遇到数字或小数点时,截取数值子串将其转换成double类型的小数,存入od栈中。

当遇到操作符,从栈中取出两个数,进行计算后再放入栈中。

继续扫描,知道扫描结束,此时值栈中的数值就是计算的结果,取出返回计算结果。

2.两个栈实现算法此算法需要两个栈,一个值栈od,一个操作符栈op。

将用户输入的数学表达式存入str数组中,对其数组进行逐个扫描。

当遇到数字或小数点,截取数值子串,将其转换成double类型的数值存入od栈中;当遇到左括号,直接入op栈;遇到右括号,op栈出栈,再从值栈od中取出两个数值,计算将其结果存入值栈中,一直进行此操作,直到操作符栈栈顶为左括号,将左括号丢掉。

如果遇到操作符,若op栈为空,直接入栈;若栈不为空,与栈顶元素比较优先等级,若比栈顶操作符优先等级高,直接入op栈,如果低于或等于栈顶优先等级,op栈出栈,再从值栈中取出两个数值,计算将其结果存入值栈中,一直进行此操作,直到栈顶优先等级低于扫描的操作符等级,将此操作符入op栈。

后缀表达式转换和计算

后缀表达式转换和计算

后缀表达式转换和计算将一个表达式转换成后缀表达式,并利用后缀表达式进行计算时,需要使用两个栈。

将一个中缀表达式转换成后缀表达式,需要用运算符栈进行;利用后缀表达式进行计算,则需要一个操作数栈。

转换时,首先定义各个运算符的优先级,才能根据规则实现转换。

具体程序如下:#include <malloc.h>#include <stdio.h>#include <ctype.h>#include <string.h>#define maxsize 100typedef struct sqstack{ /*运算符栈*/char stack[maxsize];int top;}sqstack;typedef struct sqstack2{ /*操作数栈*/int stack[maxsize];int top;}sqstack2;void Convert(char *exp,char *result);char op[6]={'+','-','*','/','(','#'}; /*运算符字符*/int pre[6]={1,1,2,2,0,-1}; /*运算符优先级*/void Initstack(sqstack *s){ /*运算符栈初始化*/s->top=0;}void Push(sqstack *s,char x){ /*运算符栈入栈*/if (s->top==maxsize-1) printf("Overflow1\n");else{s->stack[s->top]=x;s->top++;}}void Pop(sqstack *s,char *x){ /*运算符栈出栈*/if (s->top==0) printf("underflow1\n");else{s->top--;*x=s->stack[s->top];}}char Gettop(sqstack s){ /*运算符栈取栈顶元素*/ if (s.top==0){printf("underflow3\n");return 0;}else return s.stack[s.top-1];}void Initstack2(sqstack2 *s){ /*操作数栈初始化*/ s->top=0;}void Push2(sqstack2 *s,int x){ /*操作数栈入栈*/ if (s->top==maxsize-1) printf("Overflow2\n");else{s->stack[s->top]=x;s->top++;}}void Pop2(sqstack2 *s,int *x){ /*操作数栈出栈*/ if (s->top==0) printf("underflow2\n");else{s->top--;*x=s->stack[s->top];}}char f(char c){ /*定位运算符在对应数组的下标*/ switch (c) {case '+': return 0;case '-': return 1;case '*': return 2;case '/': return 3;case '(': return 4;case ')': return 5;default: return 6;}}int precede(char c1,char c2){ /*计算运算符优先级的大小*/int i1=f(c1);int i2=f(c2); /*找到字符在f数组中的位置,以方便确定其优先等级*/return pre[i1]-pre[i2];}int Operate(int a,char theta,int b){ /*对制定的操作数进行theta运算*/int sum;switch (theta) {case '+': sum=a+b; break;case '-': sum=a-b; break;case '*': sum=a*b; break;case '/': sum=a/b;}return sum;}void Convert(char *exp,char *result){ /*将中缀表达式串转换成后缀表达式串,用空格间隔各项*/sqstack OPTR;char c,x;int i=0;Initstack(&OPTR);Push(&OPTR,'#');while(*exp!='\0'){c=*exp++;if(isdigit(c)) { /*若为操作数,直接送后缀表达式*/while(isdigit(c)) {result[i++]=c;c=*exp++;}result[i++]=' ';exp--;continue;}if(c==')'){ /*若为')',出栈直至'('*/Pop(&OPTR,&x);while(x!='('){result[i++]=x;result[i++]=' ';Pop(&OPTR,&x);}continue;}if(c=='#'){ /*若为'#',出栈直至'#'*/Pop(&OPTR,&x);while(x!='#'){result[i++]=x;result[i++]=' ';Pop(&OPTR,&x);}break; /*表达式串处理结束*/}if(c=='(') { /*若为'(',直接入栈*/Push(&OPTR,c);continue;}else{ /*否则为运算符,与栈顶运算符比较*/if(precede(c,Gettop(OPTR))>0) Push(&OPTR,c); /*若优先级大于栈顶运算符,直接入栈*/else{ /*否则,优先级小于等于栈顶运算符*/Pop(&OPTR,&x); /*栈顶运算符出栈*/result[i++]=x;result[i++]=' ';while(precede(c,Gettop(OPTR))<=0){Pop(&OPTR,&x); /*栈顶运算符出栈*/result[i++]=x;result[i++]=' ';}Push(&OPTR,c);}continue;}}result[i++]='\0';}int Evalution(char *npl){sqstack2 OPND;int a,b,sum,result;char c;Initstack2(&OPND);while(*npl){c=*npl++;if(isdigit(c)){sum=0;while (isdigit(c)) {sum=sum*10+(c-'0');c=*npl++;}Push2(&OPND,sum);/*把数字串转化成十进制数字再压栈*/}else{Pop2(&OPND,&b);Pop2(&OPND,&a);Push2(&OPND,Operate(a,c,b));npl++;}}Pop2(&OPND,&result);return result;}int main(){char result[80],exp[80];printf("输入你的算术表达式,参与运算的都是正整数,不需输入等号,以#结束输入:\n");gets(exp); /*输入中缀表达式串*/Convert(exp,result); /*转换成后缀表达式串*/puts(result); /*输出后缀表达式串*/printf("The result is %d",Evalution(result)); /*利用后缀表达式计算并输出结果*/return 0;}。

后缀表达式计算规则

后缀表达式计算规则

后缀表达式计算规则
后缀表达式的计算规则是:
1. 当遇到操作数(数字)时,将其入栈。

2. 当遇到操作符时,取出栈顶的两个元素,根据当前操作符进行计算,将计算结果再压入栈顶。

3. 如果表达式是规整的表达式,在整个表达式扫描完成之后,栈顶将只有一个数字,该数据即为计算结果。

4. 不包含括号,运算符放在两个运算对象的后面。

所有计算均按运算符出现的顺序(不再考虑乘除优先于加减这种运算符的优先规则),严格从左向右进行。

按照以上步骤进行计算,就可以得出最终结果。

中缀、前缀、后缀表达式的运算

中缀、前缀、后缀表达式的运算

中缀、前缀、后缀表达式的运算 中缀表达式,就是在表达式中,操作符在操作数的中间,⽐如 (1+2)*3,+和*在1, 2, 3的中间。

前缀表达式,就是操作符在操作数的前⾯,⽐如 +12,+在1, 2的前⾯。

后缀表达式,就是操作符在操作数的后⾯,⽐如 12+,+在1, 2的后⾯。

为什么会有这么多表达式呢?它们⽬的不同。

中缀表达式,便于我们书写,也符合我们的阅读习惯,在计算机程序中,都是写中缀表达式,但它却不利于计算机进⾏算术计算,因为涉及到优先级和括号。

前缀表达式和后缀表达式中没有括号,并且运算符的优先级也通过它们在表达式中的顺序体现出来了,有利于计算机进⾏算术运算。

前缀表达式也叫波兰表达式,因为它是由⼀个波兰⼈发明的,相应的,后缀表达式也称为逆波兰表达式。

举个例⼦来说明⼀下三者的运算过程,假设计算(3+4)*5-6 使⽤中缀表达式进⾏计算 1,创建两个栈,⼀个是数字栈,⽤来存放操作数,⼀个是字符栈,⽤来存放操作符。

2,算术表达式是⼀个字符串,从左到右循环遍历表达式,依次取出每⼀个字符。

当取出的字符是操作数时,⼊数字栈。

当取出的字符是操作符时,这时还要看操作符的优先级和字符栈是否为空 如果字符栈为空,直接把取出的字符放⼊到字符栈中。

如果字符栈不为空,则要⽐较字符的优先级 如果取出的字符的优先级⼤于等于字符栈中栈顶的字符的优先级,直接把取出的字符放⼊到字符栈中。

如果取出的字符的优先级⽐字符栈中栈顶的字符的优先级低,则要循环进⾏如下操作,直到取出的字符的优先级⼤于等于字符栈中栈顶字符的优先级或者栈为空,此时,把取出的字符放⼊到字 符栈中。

如下操作就是: 1,从字符栈中弹出操作符 2,从数字栈中弹出两个操作数。

3,操作数结合操作符进⾏计算,要注意操作数顺序,后⾯pop出的数在求值的表达式中是前⾯的操作数,尤其是在做减法的时候 4,计算出的值放⼊到数字栈。

为什么要⽐较操作符的优先级呢?因为要确定操作数属于哪个操作符,相邻两个操作符之间的数字是共享的。

中缀表达式转后缀表达式并计算结果C语言版

中缀表达式转后缀表达式并计算结果C语言版
void suffixExpression(void)
{
int i = 0;
int tmpTop;
double num1,num2;
for(i = 0;i<topCal;i++)
{
stackCalBack[i] = stackCal[i];
}
i = 0;
tmpTop = topCal;
topCal = 0;
return stackCal+(--topCal);
}
/*****************************************************************
*计算表达式入栈
*****************************************************************/
break;
case ')':
while((tmpOper = stackOperPop()) != '(')
{
stackCalPush(tmpOper, IS_OPER);
}
pStr++;
islastNum = 0;
break;
case '0':case '1':case '2':case '3':case '4':
*操作符出栈
*****************************************************************/
char stackOperPop(void)
{
if(topOper == 0)return 0;

后缀算术表达式求值

后缀算术表达式求值

实验名称:后缀算术表达式求值背景描述:表达式求值是程序设计语言编译中的一个最基本的问题。

因为任何程序设计语言都必须具有表达式求值的功能,同时表达式的计算应用也相当广泛,比如电力调度系统中的计算遥测、车站票务系统中的票价类型计算公式等。

通常,我们所说的表达式是由运算符、操作数、界限符所组成。

而算术表达式中最常见的表示法形式有中缀、前缀和后缀表示法。

中缀表示法是书写表达式的常见方式,而前缀和后缀表示法主要用于计算机科学领域。

一、表达式表示法1、中缀表达式---将运算符放在两操作数的中间。

在运算中存在运算符的优先权与结合性的问题。

例如运算:a*b+(c-d/e)*f 时,编译器即自左向右逐一检查,当检查到第一个运算符"*"时还无法知道是否执行;待检查到第二个运算符" + "时,因为知道"*"的优先级别高于" + "时,才知道执行"a*b";当继续检查到" ( "时,可知道先执行括号以内部分等。

2、前缀表达式---将运算符放在两操作数的前面。

这种表示法经常用于计算机科学,特别是编译器设计方面。

为纪念其发明家-Jan Lukasiewicz,这种表示法也称波兰表示法。

3、后缀表达式---将运算符放在两操作数的后面。

后缀表达式也称逆波兰表达式,因其使表达式求值变得轻松,所以被普遍使用。

前缀和后缀表示法有三项公共特征:(1)操作数的顺序与等价的中缀表达式中操作数的顺序一致;(2)不需要括号;(3)操作符的优先级不相关。

问题描述:读入一个后缀表达式表达式,利用堆栈来计算该表达式的值,同时要效验后缀表达式是否正确。

输入输出格式:第一种方式:输入:在字符界面上输入一个后缀表达式,其中两相邻操作数之间利用空格隔开。

以"#"表示结束。

输出:如果该后缀表达式正确,那么在字符界面上输出其结果,计算结果小数点后面保留两位有效数字,如果不正确,请在字符界面上输出表达式错误提示。

C语言后缀表达式计算

C语言后缀表达式计算

一、设计思想计算算数表达式并求值,采取的共有两种方法:1.先将算数表达式转化为后缀表达式,然后对后缀表达式进行计算。

2.对算数表达式进行直接的计算。

第一种算法这种解决方案又分为两步:1.将表达式先转化为后缀表达式的字符串数组2.利用后缀表达式进行计算在转化过程中,第一,建立一个存符号的栈,和一个字符串数组,用来存放转化以后的表达式然后,对于得到的用户输入的字符串进行逐个的扫描,如果是数组或者小数点,则直接存放到数组中,并且在后面加入一个分隔符,如果是操作符,则和栈中的已存的进行比较,如果比栈中的操作符的优先级高,则直接入栈,如果优先级低或相等,则栈中元素出栈,存到字符串中,然后再次检查栈顶,直到栈中元素的优先级低于扫描操作符,则此操作符入栈,然后扫描下一个字符,直到遇到字符串的结束符号\0,扫描结束。

数组中存的就是后缀表达式。

得到后缀表达式后,进行计算,要用到数值栈。

首先要将字符表示的数字转化为浮点小数,然后进行扫描,遇到数值,放入栈中,遇到操作符,就从栈中取出两个数,进行计算后再放入栈中,扫描下一个,最后的计算结果就存到了栈中,直接取出栈内元素,就是计算的最后结果。

第二种算发首先要建立两个栈,一个用来存放操作符,一个用来存放数值。

开始对用户输入的字符串进行扫描,如果是数字字符或者小数点,则将字符转化为浮点数存到数栈里,如果是操作符,则观察符号栈,如果栈顶元素的优先级低于观察的操作符,则操作符入栈,如果栈顶元素的优先级高于或者等于观察的操作符,则从数值栈中取出两个浮点数,从符号栈中取出栈顶的操作符,然后进行相应的数值计算,所得的结果再存到数值栈中,重复这样的操作,直到符号栈中栈顶元素的优先级低于观察的操作符,则此操作符入栈,然后对下一个字符进行扫描。

如果是左括号,则不进行优先级的比较,直接入栈,入栈后优先级为-1。

如果是右括号,则从数值栈中取两个操作数,符号栈中取出一个符号,然后进行计算后得数放入数栈中,不断进行此类操作,直到从栈中取出的是左括号为止,左括号去掉,扫描下一个。

后缀表达式的算法和实现

后缀表达式的算法和实现

数据结构—中缀表达式转后缀表达式算法及实现—栈的应用—计算表达式(C++代...理论:(这部分很重要,看明白了,可以写出实现算法)表达式的表示形式有中缀、前缀和后缀3中形式。

中缀表达式按操作符的优先级进行计算(后面代码实现只包括+、-、*、\,小括号),即数学运算。

后缀表达式中只有操作数和操作符。

操作符在两个操作数之后。

它的计算规则非常简单,严格按照从左到右的次序依次执行每一个操作。

每遇到一个操作符,就将前面的两个数执行相应的操作。

由后缀表达式计算中缀表达式原理:计算机处理后缀表达式求值问题是比较方便的,即将遇到的操作数暂存于一个操作数栈中,凡是遇到操作数,便从栈中pop出两个操作数,并将结果存于操作数栈中,直到对后缀表达式中最后一个操作数处理完,最后压入栈中的数就是后最表达式的计算结果。

中缀表达式转换为等价的后缀表达式中缀表达式不方便与计算机处理,通常要讲中缀表达式转换为一个与之等价的后缀表达式。

等价是指两个表达式的计算顺序和计算结果完全相同。

中缀表达式:0.3/(5*2+1)#的等价后缀表达式是:0.3 5 2 * 1 + /#仔细观察这两个等价的表达式可知,操作数的出现次序是相同的,但运算符的出现次序是不同的。

在后缀表达式中,运算符的出现次序是实际进行操作的次序;在中追表达式中,由于受到操作符的优先级和括号的影响,操作符出现次序与实际进行操作的次序很可能是不一样的。

算法描述:将中缀表达式转换为等价的后缀表达式的过程要使用一个栈放“(”,具体可以按照下面的方式进行。

(1)从左到右一次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。

(2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号的操作处理完毕。

后缀表达式计算过程

后缀表达式计算过程

后缀表达式计算过程嘿,朋友们!今天咱们来唠唠后缀表达式的计算,这就像是一场超级有趣的数字冒险呢!你看啊,后缀表达式就像是一群数字和符号排着特别的队伍。

那些数字就像是一个个小士兵,乖乖地站在那儿,而符号呢,就像是小士兵的指挥官。

比如说“3 4 +”,3和4这俩小士兵就等着“+”这个指挥官发号施令。

这就好比是在一个魔法世界里,数字们都有自己的使命,等待着被组合或者运算。

计算的时候啊,就像是在玩一个神奇的搭积木游戏。

我们先找到两个数字小士兵,就像从一堆彩色积木里挑出两块一样。

比如看到“5 6 *”,那我们就先把5和6这两块“积木”拿出来,然后按照“*”这个指令让它们相乘,就像把两块积木拼接成一个新的形状,得到30这个新的“积木块”。

有时候呢,这个队伍里会有很多小士兵和指挥官。

要是遇到“2 3 + 4 *”,我们就先让2和3这俩小士兵被“+”指挥官指挥,得到5这个新小士兵,然后这个5小士兵又和4小士兵被“*”指挥官指挥,就像接力比赛一样,最后得到20这个超级厉害的结果。

这计算过程还像一场数字的舞蹈派对呢。

数字们按照后缀表达式的音乐节奏(规则)跳动、组合。

符号就是舞蹈动作的指示牌,告诉数字们该怎么旋转、拥抱(运算)。

要是表达式长一点,就像是一个超级复杂的魔术表演。

魔术师(我们)要一步步按照魔法咒语(计算规则)来操作。

比如说“1 2 + 3 4 - *”,我们得先搞定1和2的加法,3和4的减法,然后再把得到的结果进行乘法,就像从一个魔法帽子里变出最终的兔子(答案)一样神奇。

而且啊,每一次计算就像是打开一个神秘的数字宝藏。

我们顺着后缀表达式这个神秘的地图,一路探索,最后找到那个闪闪发光的宝藏(结果)。

这个宝藏可能是一个小小的数字,也可能是一个超级大的数字,不管怎样,找到它的过程就充满了惊喜和乐趣。

想象一下,后缀表达式是一个数字的王国,数字们在这个王国里遵循着特殊的法则生活。

我们计算的时候,就像是这个王国的超级管理员,指挥着数字们按照我们的意愿进行各种有趣的活动,最终让这个王国达到一种和谐的状态(得出正确结果)。

后缀表达式求值的算法及代码

后缀表达式求值的算法及代码

#include<stdlib.h>#include<stdio.h>struct node // 栈结构声明{int data; // 数据域struct node *next; // 指针域};typedef struct node stacklist; // 链表类型typedef stacklist *link; // 链表指针类型link operand=NULL; // 操作数栈指针link push(link stack,int value) // 进栈{link newnode; // 新结点指针newnode=new stacklist; // 分配新结点if (!newnode){printf("分配失败!");return NULL;}newnode->data=value; // 创建结点的内容newnode->next=stack;stack=newnode; // 新结点成为栈的开始return stack;}link pop(link stack,int *value) // 出栈{link top; // 指向栈顶if (stack !=NULL){top=stack; // 指向栈顶stack=stack->next; // 移动栈顶指针*value=top->data; // 取数据delete top; // 吸收结点return stack; // 返回栈顶指针}else*value=-1;}int empty(link stack) // 判栈空{if (stack!=NULL)return 1;elsereturn 0;}int isoperator(char op) // 判运算符{switch (op){case'+':case'-':case'*':return 1; // 是运算符,返回1case'/':return 0; // 不是运算符,返回0}}int getvalue(int op,int operand1,int operand2) // 计算表达式值{switch((char)op){case'*':return(operand1*operand2);case'/':return(operand1/operand2);case'+':return(operand1+operand2);case'-':return(operand1-operand2);}}void main() // 主函数{char exp[100];int operand1=0; // 定义操作数1int operand2=0; // 定义操作数2int result=0; // 定义操作结果int pos=0;printf("\t\n 请输入后缀表达式:");gets(exp); // 读取表达式printf("\t\n\n 后缀表达式[%s]的计算结果是:",exp);while (exp[pos] !='\0' && exp[pos] !='\n') // 分析表达式字符串{if (isoperator(exp[pos])) // 是运算符,取两个操作数{operand=pop(operand,&operand1);operand=pop(operand,&operand2);operand=push(operand,getvalue(exp[pos],operand1,operand2));// 计算结果入栈}elseoperand=push(operand,exp[pos]-48); // 是操作数,压入操作数栈pos++; // 移到下一个字符串位置}operand=pop(operand,&result); // 弹出结果printf("%d\n",result); // 输出}。

后缀表达式计算结果

后缀表达式计算结果

后缀表达式计算结果(栈的应用)
后缀表达式为:9 3 1 - 3 * + 10 2 / +
规则为:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。

a.初始化一个空栈。

此栈用来对要运算的数字进行进出使用。

b.后缀表达式中前三个是、都是数字,所以9 3 1 进栈。

c.接下来是“-”,所以将栈中的1出栈作为减数,3出栈作为被减数,并运算3-1得到2,再讲2进栈。

d.接着是数字3进栈。

e.后面是“*”,也就意味着栈中3和2出栈,2与3相乘,得到6,并将6进栈。

f.下面是“+”,所以栈中6和9出栈,9和6相加,得到15,将15进栈。

g.接着是10和2两数字进栈。

h.接下来是符号“/”,因此,栈顶的2与10出栈,10与2相除,得到5,将5进栈。

i.最后一个是符号“+”,所以15与5出栈并相加,得到20,讲20进栈。

j.结果是20出栈,栈变为空。

后缀算术表达式

后缀算术表达式

后缀算术表达式后缀表达式的特点如下:1、后缀表达式的操作数与中缀表达式的操作数先后次序相同,⽽运算符的先后次序不同。

2、后缀表达式中没有括号,⽽且运算符没有优先级。

3、后缀表达式计算过程严格按照从左到右的顺序进⾏。

例如:算术表达式a+(b-c)*d的后缀式是:abc-d*+在输⼊的时候出了问题:string s;cin>>s; 不能输⼊空格所以要⽤getlinegetline(cin,s);头⽂件 string 或者istream#include<iostream>#include<string>#include<istream>#include<cstring>#include<iomanip>using namespace std;typedef struct StackNode *LStack;struct StackNode {double nu;LStack next;};void Init(LStack &s){s = new StackNode;s = NULL;}void Pushnu(LStack &s, double c){LStack p = new StackNode;p->nu = c;p->next = s;s = p;}void Pop(LStack &s){LStack p;p = s;if (!s->next)s = NULL;elses = s->next;delete p;}double GetTopnu(LStack &s){return s->nu;}int main(){string s;s = "";cout << setiosflags(ios::fixed) << setprecision(2);while (s != "="){getline(cin, s);char *ptr;int length = 0;LStack p;//s1是数字,s2是运算符 Init(p);for (int i = 0; i <s.size(); i++){if (s[i] >= '0'&&s[i] <= '9'){Pushnu(p, s[i] - 48);}elseif (s[i] == '+'){double a, b;a = GetTopnu(p);Pop(p);b = GetTopnu(p);Pop(p);double c;c = a + b;Pushnu(p, c);}else{if (s[i] == '-'){double a, b;a = GetTopnu(p);Pop(p);b = GetTopnu(p);Pop(p);double c;c = b - a;Pushnu(p, c);}elseif (s[i] == '*'){double a, b;a = GetTopnu(p); Pop(p);b = GetTopnu(p); Pop(p);double c;c = b * a;Pushnu(p, c);}else{if (s[i] == '/'){double a, b;a = GetTopnu(p); Pop(p);b = GetTopnu(p); Pop(p);double c;c = b / a;Pushnu(p, c);}elseif (s[i] == '=')break;elseif (s[i] == '') {continue; }}}}if (s == "=")return0;cout << p->nu << endl;}return0;}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、设计思想计算算数表达式并求值,采取的共有两种方法:1.先将算数表达式转化为后缀表达式,然后对后缀表达式进行计算。

2.对算数表达式进行直接的计算。

第一种算法这种解决方案又分为两步:1.将表达式先转化为后缀表达式的字符串数组2.利用后缀表达式进行计算在转化过程中,第一,建立一个存符号的栈,和一个字符串数组,用来存放转化以后的表达式然后,对于得到的用户输入的字符串进行逐个的扫描,如果是数组或者小数点,则直接存放到数组中,并且在后面加入一个分隔符,如果是操作符,则和栈中的已存的进行比较,如果比栈中的操作符的优先级高,则直接入栈,如果优先级低或相等,则栈中元素出栈,存到字符串中,然后再次检查栈顶,直到栈中元素的优先级低于扫描操作符,则此操作符入栈,然后扫描下一个字符,直到遇到字符串的结束符号\0,扫描结束。

数组中存的就是后缀表达式。

得到后缀表达式后,进行计算,要用到数值栈。

首先要将字符表示的数字转化为浮点小数,然后进行扫描,遇到数值,放入栈中,遇到操作符,就从栈中取出两个数,进行计算后再放入栈中,扫描下一个,最后的计算结果就存到了栈中,直接取出栈内元素,就是计算的最后结果。

第二种算发首先要建立两个栈,一个用来存放操作符,一个用来存放数值。

开始对用户输入的字符串进行扫描,如果是数字字符或者小数点,则将字符转化为浮点数存到数栈里,如果是操作符,则观察符号栈,如果栈顶元素的优先级低于观察的操作符,则操作符入栈,如果栈顶元素的优先级高于或者等于观察的操作符,则从数值栈中取出两个浮点数,从符号栈中取出栈顶的操作符,然后进行相应的数值计算,所得的结果再存到数值栈中,重复这样的操作,直到符号栈中栈顶元素的优先级低于观察的操作符,则此操作符入栈,然后对下一个字符进行扫描。

如果是左括号,则不进行优先级的比较,直接入栈,入栈后优先级为-1。

如果是右括号,则从数值栈中取两个操作数,符号栈中取出一个符号,然后进行计算后得数放入数栈中,不断进行此类操作,直到从栈中取出的是左括号为止,左括号去掉,扫描下一个。

扫描结束后,计算也结束了,计算的结果就存放在数值栈中,最后把数值栈中的数取出,就是所得的计算结果。

容错的算法简要:括号匹配:当扫描到左括号是,左括号直接入栈,扫描到右括号时,则左括号出栈,如果栈为空,则右括号多,如果最后栈中还有括号,则左括号多。

给出错误提示。

除数不为0:当扫描到'/'时,就判断其后面的数字是否为0,如果为0报错。

取余运算:取余运算时,操作数判断是否为整数,不为整数报错。

二、算法流程图第一种算法:先将表达式转化为后缀表达式,然后计算其主函数流程图为:图1 主函数算法流程图其中将中缀表达式转化为后缀表达式的主要流程为:图2 中缀转化为后缀算法流程图存在错误 报错并结束后缀表达式的计算,实现的流程图为:图3 后缀表达式计算算法流程图下面介绍直接计算出结果的算法的实现:图4 直接计算中缀表达式算法流程图三、源代码下面给出的是用先转后缀再计算和直接计算的算法实现的程序的源代码:#include<stdio.h> /*导入需要用到的各种包*/#include<stdlib.h>#include<string.h>typedef struct /*定义结构体用来存储操作符*/{char op; /*存储字符*/int level; /*存储优先级*/}OpNode;typedef struct{OpNode op[100];int top;int size; /*表示栈内元素的个数*/} stack; /*定义符号栈*/void init(stack *st) /*初始化栈*/{st->size=0;st->top=0;}OpNode pop(stack *a) / *出栈*/{if (a->size==0) /*如果栈为空结束操作*/{exit(-1);}a->size--;return a->op[--(a->top)]; /*取出栈顶元素*/}void push(stack *a,OpNode op) /*入栈函数*/{a->size++;a->op[(a->top)++]=op;}OpNode top(stack *a) /*观察栈顶函数*/{if (a->size==0) /*如果栈为空结束操作*/{printf("stack is empty\n");exit(-1);}return a->op[(a->top)-1]; /*只得到栈顶的值而不出栈*/}typedef struct /*定义数值栈*/{double num[100];int top; /*栈顶指针*/int size;} numstack;void init2(numstack *st) /*初始化数值栈*/{st->size=0;st->top=0;}double pop2(numstack *a) /*数值栈出栈*/{if (a->size==0) /*出栈前的判空*/{exit(-1);}a->size--;return a->num[--(a->top)]; /*得到栈顶的值*/}void push2(numstack *a,double num) /*入栈*/{a->size++;a->num[(a->top)++]=num;}void main() /*主函数*/{void change (char str[],char exp[]); /*声明要用到的各个函数*/double CalResult(char exp[]); /*声明后缀表达式的计算函数*/double Directcalresult(char str[]);int check(char str[],char chestr[100]);char str[100],exp[100],chestr[100]; /*str存储原算术表达式,exp存储对应的printf("算术表达式为:\n"); 后缀表达式,chestr存储容错字符'^'*/ gets(str);if(check(str,chestr)) /*调用容错函数*/{ printf("表达式错在:\n");printf("%s\n",str);printf(chestr); /*根据输入情况指出错误的地方*/exit(-1);}change(str,exp); /*调用函数将中缀转化为后缀*/printf("后缀表达式为:%s\n",exp);printf("运算结果为:%f\n",CalResult(exp)); /*调用函数计算后缀表达式*/ printf("直接运算的结果为: %f\n",Directcalresult(str)); /*调用直接计算函数*/ }void change (char str[],char ch[]) /*将前缀表达式转化为后缀表达式*/{int i=0; /*str的索引*/int k=0;char c; /*字符串中取出的放在C中*/stack st; /*定义符号栈*/OpNode op;OpNode ops;init(&st); /*初始化符号栈*/c=str[i++];while (c!='\0') /*对字符串进行扫描*/{if ( (c>='0'&&c<='9')||c=='.') /*如果字符为数字或小数点*/{while ( (c>='0'&&c<='9')||c=='.'){ch[k++]=c; /*将字符直接放入数组中*/c=str[i++];}ch[k++]='|'; /*在其后面放入一个分隔符*/}if (c=='(') /*如果字符是左括号*/{op.op='(';op.level=-1; /*定义其优先级为-1*/push(&st,op); /*将左括号直接入栈*/}if(c==')') /*如果字符为右括号*/{op=top(&st); /*首先观察栈顶*/while (st.size!=0&&op.op!='(') /*如果不是左括号并且栈不为空*/{op=pop(&st); /*出栈并存入数组中*/ch[k++]=op.op;if (st.size>0) /*再次检查栈是否为空,*/op=top(&st);else break; /*为空就结束*/}pop(&st); /*去掉左括号*/}if (c=='+'||c=='-') /*如果是+-号*/{op.op=c;op.level=1; /*优先级为1*/if (st.size==0){push(&st,op); /*如果此时栈为空直接入栈*/ }else{ops=top(&st); /*观察栈顶*/while (ops.level>=op.level) /*如果栈顶优先级高*/{ops=pop(&st);ch[k++]=ops.op; /*将栈顶元素取出存入数组中*/if (st.size>0)ops=top(&st); /*进行判空操作,栈为空结束*/elsebreak;}push(&st,op); /*此时栈顶优先级低,入栈*/ }}if(c=='*'||c=='/'||c=='%') /*如果是*/进行*/{op.op=c;op.level=2; /*优先级为1*/if (st.size==0){push(&st,op); /*如果此时栈为空直接入栈*/ }else{ops=top(&st); /*观察栈顶*/while (ops.level>=op.level) /*如果栈顶优先级高*/{ops=pop(&st); /*将栈顶元素取出存入数组中*/ch[k++]=ops.op;if (st.size>0)ops=top(&st); /*进行判空操作,栈为空结束*/ elsebreak;}push(&st,op); /*此时栈顶优先级低,入栈*/}}c=str[i++]; /*索引自加检索下一个字符*/}while(st.size!=0) /*最后判断栈如果不为空*/ {ops=pop(&st); /*取出栈内元素存入数组中*/ch[k++]=ops.op;}ch[k]='\0'; /*将\0作为结尾存入数组*/}double CalResult(char exp[]) /*后缀表达式的计算*/{char c;numstack numst; /*建立数值栈*/double d1,d2,dr;int k=0; /*后缀表达式的索引*/int i=0; /*将字符转化为浮点数的索引*/ char *s;char trans[100]; /*存字符表示的一段数字*/init2 (&numst); /*实现数值栈*/c=exp[k++];while (c!='\0') /*开始扫描后缀表达式*/{if(c=='+'||c=='-'||c=='*'||c=='/'||c=='%') /*如果是操作符*/{switch(c){case '+' : /*如果是加法操作*/d2=pop2(&numst);d1=pop2(&numst);dr=d1+d2; /*相加后入栈*/push2(&numst,dr);break;case '-' : /*如果是减法操作*/d2=pop2(&numst);d1=pop2(&numst);dr=d1-d2; /*相减后入栈*/push2(&numst,dr);break;case '*' : /*如果是乘法操作*/d2=pop2(&numst);d1=pop2(&numst);dr=d1*d2; /*相乘后入栈*/push2(&numst,dr);break;case '/' : /*如果是除法操作*/d2=pop2(&numst);d1=pop2(&numst);dr=d1/d2; /*相除后入栈*/push2(&numst,dr);break;case '%' : /*如果是取余操作*/d2=pop2(&numst);d1=pop2(&numst);dr=(double)((int)d1%(int)d2); /*类型转化并取余后入栈*/push2(&numst,dr);break;}}if (c>='0'&&c<='9'||c=='.') /*如果是字符表示的数字*/{while(c>='0'&&c<='9'||c=='.'){trans[i++]=c; /*将字符存入数组进行下一个的扫描*/c=exp[k++];}trans[i++]='\0'; /*将表示数字的字符串结束*/i=0;s=trans; /*将指针指向该数组*/d1=atof(s); /*利用函数将字符串转化为浮点数*/push2(&numst,d1);}c=exp[k++];}return pop2(&numst); /*最后结果将在数值栈中,取出作为返回值*/ }double Directcalresult(char str[]) /*表达式的直接计算出结果*/{stack ms; /*建立符号栈*/numstack mns; /*建立数值栈*/double calculate(double od1,double od2,OpNode op);int index=0; /*str的索引*/int len=strlen(str);char c;char trans[100]; /*存放数值的一段字符*/int i=0; /*trans的索引*/char * s;double d;OpNode tempn; /*存放当前扫描的操作符*/OpNode templn;double oda,odb,odr;double result; /*作为返回值返回结果*/init (&ms); /*实现两个栈*/init2(&mns);while(index<len) /*开始对用户输入的表达式进行扫描*/ {c=str[index++];if(c>='0'&&c<='9'||c=='.') /*如果是数字字符或小数点*/{while(c>='0'&&c<='9'||c=='.'){trans[i++]=c; /*将其存入数组扫描下一个*/c=str[index++];}trans[i++]='\0'; /*扫描完一个数结束数组*/i=0; /*索引归0*/s=trans;d=atof(s);push2(&mns,d); /*转化为浮点数入栈*/ }if(c=='+'||c=='-') /*如果是+-*/{tempn.level=1; /*优先级设为1*/tempn.op=c;if(ms.size==0){push(&ms,tempn); /*栈为空直接入栈*/}else{templn=top(&ms);while (templn.level>=tempn.level) /*栈顶优先级高*/{templn=pop(&ms); /*取出操作数和操作符计算*/odb=pop2(&mns);oda=pop2(&mns);odr=calculate(oda,odb,templn);push2(&mns,odr); /*结算结果入栈*/if(ms.size>0){templn=top(&ms); /*如果栈空结束*/}elsebreak;}push(&ms,tempn); /*操作符入栈*/}}if(c=='*'||c=='/'||c=='%') /*如果是*/%操作*/{tempn.level=2; /*定义优先级为2*/tempn.op=c;if(ms.size==0){push(&ms,tempn); /*栈空直接入栈*/}else{templn=top(&ms);while (templn.level>=tempn.level) /*栈顶优先级高*/{templn=pop(&ms); /*取出操作数和操作符计算*/ odb=pop2(&mns);oda=pop2(&mns);odr=calculate(oda,odb,templn);push2(&mns,odr); /*结算结果入栈*/if(ms.size>0){templn=top(&ms);}elsebreak; /*如果栈空结束*/templn=top(&ms);}push(&ms,tempn); /*操作符入栈*/}}if(c=='(') /*如果是左括号*/{tempn.level=-1;tempn.op=c; /*直接入栈优先级定位-1*/push(&ms,tempn);}if(c==')') /*如果是右括号*/{while(tempn.op!='(') /*遇到左括号结束*/{templn=pop(&ms);odb=pop2(&mns); /*从数栈中取两个数,从符号栈里取操作符*/oda=pop2(&mns);odr=calculate(oda,odb,templn); /*计算出结果入栈*/push2(&mns,odr);if (ms.size>0)tempn=top(&ms);elsebreak; /*如果栈空结束*/}pop(&ms); /*取出左括号*/}}tempn=top(&ms);while(1){templn=pop(&ms);odb=pop2(&mns); /*从数栈中取两个数,从符号栈里取操作符*/oda=pop2(&mns);odr=calculate(oda,odb,templn); /*计算出结果入栈*/push2(&mns,odr);if (ms.size>0)tempn=top(&ms); /*如果栈空结束*/elsebreak;}result =pop2(&mns); /*最后的结果在数值栈中返回*/return result;}double calculate(double od1,double od2,OpNode op) /*已知操作符和操作数的计算*/ {switch(op.op){case '+' : return od1+od2;case '-' : return od1-od2; /*判断操作符是哪个执行相应计算*/case '*' : return od1*od2;case '/' : return od1/od2;case '%' : return (double)((int)od1%(int)od2);}return 0; /*如果上面的都没有执行返回0*/}int check(char str[],char chestr[100]) /*容错函数*/{char c;char cdivide;int i=0; /*str的索引*/stack che; /*括号匹配用到的栈*/OpNode temp;int k=0; /*chestr的索引*/int isinteger(char integer[100]); /*%计算是判断是否是整数*/char s1[10]; /*%操作时存储%左右的数字*/char s2[10];int indexs1=0; /*s1s2的索引*/int indexs2=0;init (&che);int flag=0; /*0——没有出错1——有错*/int tag=0;c=str[i]; /*开始扫描*/int j; /*数组chestr索引*/for(j=0;j<99;j++){chestr[j]=' '; /*数组初始化待以后加入'^'*/ }chestr[j]='\0';while(c!='\0'){if(c=='(') /*如果是左括号就入栈*/{temp.op=c;push(&che,temp);}if(c==')') /*如果是右括号*/{if(che.size>0){pop(&che); /*栈不为空就取出一个左括号*/ }else{flag=1;printf("缺少左括号\n"); /*否则提示有错*/chestr[i]='^'; /*右括号下加'^'*/ }}if(c=='/') /*判断除数是否为0*/{j=0;cdivide=str[i+1+j]; /*取出除号后的数*/while(cdivide>='0'&&cdivide<='9'||cdivide=='.') /*如果是数或小数点就一直存*/ {s1[j++]=cdivide;if(cdivide!='0'&&cdivide!='.') /*如果不是0则正确并结束*/{tag=1;break;}cdivide=str[i+j+1];}if(!tag) /*如果tag为0则存在错误除数为0*/{chestr[i+1]='^';flag=1; /*flag为1表示有错*/}}if(c=='%') /*取余操作的容错*/{while(str[i-indexs1-1]>='0'&&str[i-indexs1-1]<='9'||str[i-indexs1-1]=='.') /*以%为中心向前扫描*/ {s1[indexs1++]=str[i-indexs1-1]; /*如果是数或小数点*/ } /*放在s1中*/while(str[i+indexs2+1]>='0'&&str[i+indexs2+1]<='9' /*以%为中心向后扫描*/ ||str[i+indexs2+1]=='.'){ /*如果是数或小数点*/ s2[indexs2++]=str[i+indexs2+1]; /*放在s1中*/ }if(isinteger(s1)) /*调用函数判断s1内存到是否是整数*/ {printf("取余算法第一个数应为整数运算\n");flag=1; /*记录为有错*/chestr[i-indexs1]='^';}if(isinteger(s2)) /*调用函数判断s2内存到是否是整数*/{printf("取余算法第二个数应为整数运算\n");flag=1; /*记录为有错*/chestr[i+indexs2]='^';}}i++;c=str[i]; /*检索下一个字符*/ }if(che.size>0){ /*如果最后栈不为空*/printf("缺少右括号\n"); /*栈中还有没配对的左括号报错*/ }return flag; /*返回是否有错*/}int isinteger(char integer[100]) /*判断数组内是否是整数*/{int i=0; /*传过来的数组的索引*/char c;c=integer[i++];while(c!='\0') /*直到字符串最后扫描结束*/{if(c=='.') /*只要有一个字符为小数点就不是整数*/return 1;elsec=integer[i++]; /*扫描下一个*/}return 0;}四、运行结果在输入表达式没有错误的情况下,可以得到两种算法的运算结果为:图5 表达式正确时两种算法运行结果图如果表达式的输入有错误,运行结果分别如下:1.除数为0图6 除数为0提示错误图2.取余运算操作数不为整数:图7取余操作数不为整提示错误图3.括号匹配的问题:图8 缺少左括号提示错误图图9缺少右括号提示错误图五、遇到的问题及解决在编程的时候总是会有很多的意想不到的为题出现。

相关文档
最新文档