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语言前缀和后缀运算规则的简述和示例解释:前缀运算符前缀运算符是紧跟在变量或表达式之前的运算符。
它会在使用变量之前对其进行操作,然后返回操作后的值。
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语言前缀和后缀运算规则有一定的了解,并能在编程过程中正确使用它们。
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 /;数字的数位写法也是常规顺序。
C语言之逆波兰表达式完整代码(附算法)

C语言课程设计之逆波兰表达式//逆波兰表达式(后缀表达式)reverse polish notation//程序实现的功能是将中缀表达式转变为后缀表达式,再求出其值//主要运用的知识点有:isdigit函数,pow函数,system("cls")函数,堆栈,格式的强制转换#include<stdio.h>#include<ctype.h>#include<stdlib.h>#include<math.h>void shift( char notation[]); //中缀表达式转换为后缀表达式的转换函数float calculate(float a[][2],int k); //计算后缀表达式int judge(char notation[]); //判断输入的中缀表达式是否符合要求int grade(char a); //返回运算符的等级void display(float a[][2],int k); //在屏幕上显示后缀表达式//主函数void main(){char notation [100];char choice;do{printf("请输入正确的中缀表达式:\n");printf("例如:2*3+4/3-(2+1)\n");scanf("%s",¬ation);if(judge(notation)){shift(notation);}elseprintf("你的表达式有错误,请仔细检查!\n");fflush(stdin);printf("\n你是否需要继续计算(是输入Y/y,否输入其他任意键)\n");scanf("%c",&choice);getchar();system("cls");}while(choice=='Y'||choice=='y');printf("\n程序结束,谢谢使用!\n");}//判定函数int judge(char notation[]){int i,m,num=1,p1=0,p2=0;for(i=0;notation[i]!='\0';i++) //排除表达式外的字符{if(notation[i]!='('&¬ation[i]!=')'&¬ation[i]!='+'&¬ation[i]!='-'&¬ation[i]!='*'&¬ation[i]!='/'&&!isdigit(notation[i])&¬ation[i]!='.') {num=0;return num;}}if(notation[0]=='*'||notation[0]=='/'||notation[0]==')'||notation[0]=='.') //排除第一个字符为*,/,),.{num=0;return num;}for(i=0;notation[i]!='\0';i++) //排除'+','-','*','/','.'之间的连续出现以及'+','-','*','/','.'后面直接加')'{if(notation[i]!='('&¬ation[i]!=')'&&!isdigit(notation[i])){if(notation[i+1]!='('&&!isdigit(notation[i+1])){num=0;return num;}}if(notation[i]=='('&&(notation[i+1]==')'||notation[i+1]=='.'||notation[i+1]=='*'||notation[i+ 1]=='/')){ //排除'('和')','.','*','/'一起连用num=0;return num;}if(notation[i]==')'&&(notation[i+1]=='('||notation[i+1]=='.'))//排除')'和'(','.'一起连用{num=0;return num;}}for(i=0;notation[i]!='\0';i++) //小数位不得超过4位{if(notation[i]=='.'&¬ation[i+1]!='\0'&¬ation[i+2]!='\0'&¬ation[i+3]!='\0'&¬ation[i+4]!='\0'&¬ation[i+5]!='\0'){if(isdigit(notation[i+1])&&isdigit(notation[i+2])&&isdigit(notation[i+3])&&isdigit(notation[i+ 4])&&isdigit(notation[i+5])){num=0;return num;}}}for(i=0;notation[i]!='\0';i++) //排除一个小数中有两个小数点的情况{if(notation[i]=='.'){i++;while(isdigit(notation[i])){i++;}if(notation[i]=='.'){num=0;return 0;}}}for(i=0;notation[i]!='\0';i++) //排除')'后面不可以直接跟数字以及'('前面不可以加数字{if(notation[i]==')'&&isdigit(notation[i+1])){num=0;return num;}if(isdigit(notation[i])&¬ation[i+1]=='(' ){num=0;return num;}}for(i=0;notation[i]!='\0';i++) //约束数字的位数一共最多为七位{if(isdigit(notation[i])){m=0; //用来计数,数字的位数为7while(isdigit(notation[i])||notation[i]=='.'){i++;m++;if(notation[i]=='.'){m--;}}if(m>7){num=0;return num;}}}for(i=0;notation[i]!='\0';i++) //'('与')'需要配对存在{if(notation[i]=='(')p1++;if(notation[i]==')')p2++;if(p1!=p2){num=0;return num;}}return num;}//转换函数void shift( char notation[]){char s1[100];s1[0]='#';float s2[100][2]; //第一维放后缀表达式的元素,第二维表示小数点的位数以及是否是运算符int i=0,j=1,k=0,t=0;float sum,num1=0,num2=0; //num1为存储整数位num2为存储小数位while(notation[i]!='\0'){if(i==0&¬ation[i]=='+') //第一位为正号的情况{if(isdigit(notation[++i])){num1=0; //整数部分while(isdigit(notation[i])){num1=num1*10+(notation[i]-'0'); //notation[i]-'0'可以将字符转换为整数0~9i++;}num2=0; //小数部分t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float (num2+pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}if(i==0&¬ation[i]=='-') //第一位为负号的情况,代码与正号类似{if(isdigit(notation[++i])){num1=0;while(isdigit(notation[i])){num1=(-1)*num1*10+(-1)*(notation[i]-'0');i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+(-1)*pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}if(isdigit(notation[i])) //当前字符为数字的情况与为正号的情况一样{num1=0;while(isdigit(notation[i])){num1=num1*10+(notation[i]-'0');i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}if(notation[i]=='+'||notation[i]=='-'||notation[i]=='*'||notation[i]=='/'){ //当前的字符为操作符时,如果s1的站定为'('则将字符直接送入s1if(s1[j-1]=='('){s1[j++]=notation[i++];}}if(notation[i]=='+'||notation[i]=='-'||notation[i]=='*'||notation[i]=='/'){ //当前字符为操作符时的普通的情况if(grade(notation[i])>grade(s1[j-1])){s1[j++]=notation[i++];}else{s2[k++][0]=s1[--j];s2[k-1][1]=-1;s1[j++]=notation[i++];}}if(notation[i]=='(') //当前字符为'('的情况{s1[j++]=notation[i++];if(notation[i]=='+') //'('后跟正号的情况{if(isdigit(notation[++i])){num1=0;while(isdigit(notation[i])){num1=num1*10+(notation[i]-'0');i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}if(notation[i]=='-') //'('后跟负号的情况{if(isdigit(notation[++i])){num1=0;while(isdigit(notation[i])){num1=float((-1)*num1*10+(-1)*(notation[i]-'0'));i++;}num2=0;t=0;if(notation[i]=='.'){i++;while(isdigit(notation[i])){num2=float(num2+(-1)*pow(0.1,++t)*(notation[i]-'0'));i++;}}s2[k++][0]=float(num1+num2);s2[k-1][1]=float(t);}}}if(notation[i]==')') //当前字符为')'的情况{while(s1[--j]!='('){s2[k++][0]=s1[j];s2[k-1][1]=-1;}i++;}}while(j>0&&s1[--j]!='#') //依次将s1中的除了'#'外的所有操作符出栈,相当于最后的扫尾工作{s2[k++][0]=s1[j];s2[k-1][1]=-1;}printf("\n后缀表达式(逆波兰表达式):\n");display(s2,k-1);printf("\n表达式的值为:\n");sum=calculate(s2,k-1);printf("%7.4f",sum);}//计算函数float calculate(float a[][2],int k){int i,t=0,j=k;float b[100][2],c[100];for(i=k;i>=0;i--){b[i][0]=a[k-i][0];b[i][1]=a[k-i][1];}i=k;while(j>=0){if(b[i][1]!=-1){c[t]=float (b[i][0]);j--;i--;t++;}if(b[i][1]==-1) //每当遇到一个运算符则将栈最上面的两个数出栈进行运算,然后再入栈{if(int(b[i][0])=='+'){c[t-2]=float (c[t-2]+c[t-1]);}if(int(b[i][0])=='-'){c[t-2]=float (c[t-2]-c[t-1]);}if(int(b[i][0])=='*'){c[t-2]=float (c[t-2]*c[t-1]);}if(int(b[i][0])=='/'){c[t-2]= float (c[t-2]/c[t-1]);}j--;i--;t--;}}return c[0]; //运算到最后,栈中的元素即为结果}//等级函数int grade(char a) //按照运算符的优先级{if(a=='#')return 0;if(a=='(')return 1;if(a=='-'||a=='+')return 2;if(a=='*'||a=='/')return 3;if(a==')')return 4;elsereturn 5;}//显示函数void display(float a[][2],int k){int i;for(i=0;i<=k;i++){if(a[i][1]==0)printf(" %d",int(a[i][0]));if(a[i][1]==1)printf(" %7.1f",a[i][0]);if(a[i][1]==2)printf(" %7.2f",a[i][0]);if(a[i][1]==3)printf(" %7.3f",a[i][0]);if(a[i][1]==4)printf(" %7.4f",a[i][0]);if(a[i][1]==-1)printf(" %c",int (a[i][0]));}}算法实现一个表达式E的后缀形式可以如下定义:(1)如果E是一个变量或常量,则E的后缀式是E本身。
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语言下表达式的自动计算(两种方式)(报告+源代码)

一、设计思想第一种算法:将中缀表达式转为后缀表达式,然后通过后缀表达式计算出算术表达式的结果。
核心思想:第一步:中缀变后缀。
首先,我们做出一个统一的Node结构体,结构体内部包含四个属性,分别是操作符的字符‘op’,char类型;操作符的优先级‘level’,int 类型;数字的浮点数数值‘od’,float类型;Node的标识符,int类型。
然后,定义一个Node结构体类型的数组*listNode,这里的*listNode用的是全局变量,为了方便在得到后缀表达式后,不需再传递给计算的方法。
定义一个存放操作符的栈,遍历用户输入的算术表达式(不考虑错误情况),在遍历的过程中如果遇到数字,直接将数字存放在*listNode里面;如果遇到了操作符,则判断操作符栈目前是不是为空,如果为空,直接将遇到的操作符放入操作符栈中,如果操作符栈不为空,那么观察操作符栈中栈顶的操作符,然后再次判断当前遇到的操作符的优先级是不是比栈顶的操作符的优先级高,如果是,那么将当前的操作符入操作符栈;如果不是,那么将操作符栈的栈顶操作符取出,追加到*listNode中,然后继续观察栈顶操作符,直到当前的操作符的优先级比栈顶操作符的优先级高或者操作符栈为空时,将当前操作符入操作符栈。
如果遇到了左括号,那么定义其优先级为最低,然后直接将左括号入操作符栈。
如果遇到了右括号,那么开始从操作符栈中取出操作符追加到*listNode中,直到遇到了与之对应的左括号,然后将左括号和右括号一起销毁。
当遍历完成了算术表达式之后,这时判断操作符栈是否为空,如果不为空,那么从操作符栈中依次取出栈顶操作符追加到*listNode中,直到操作符栈为空,那么就代表我们将中缀表达式转变成为了后缀表达式。
第二步:通过得到的后缀表达式,计算算术表达式。
首先,定义一个数字栈用来存放数值。
然后,遍历*listNode中的每一个Node,如果Node是一个数字,那么就将数字入数字栈,如果Node是一个操作符,那么就从数字栈中依次取出栈顶的两个数字,然后根据操作符计算这两个数字,将得到的结果再次入数字栈,直到遍历*listNode完成,最终数字栈中会只剩下一个Node,那就是我们计算出算术表达式的结果,将结果返回给main 函数用来输出。
中缀表达式转后缀表达式并计算结果(c语言版)

中缀表达式转后缀表达式中缀表达式转后缀表达式的规则。
1.遇到操作数:直接输入到后缀表达式栈2.遇到运算符,直接入操作符栈3.遇到左括号:直接将其入栈4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈6.最终将操作符栈中的元素依次出栈,输出到后缀表达式栈。
以下是自己写的代码。
亲测没有问题。
(模拟一个计算器,可以带括号,中间可以空格,只支持整数输入,但是输出结果精确到小数后6位)#include "stdio.h"#define MAX_LEN 100typedef struct cal{unsigned char isOper;//是否是操作数1,操作符0.操作数double Num; //值。
或者是操作符的ASCII值}STRUCT_CAL;#define IS_NUM 0x00#define IS_OPER 0x01STRUCT_CAL stackCal[MAX_LEN];STRUCT_CAL stackCalBack[MAX_LEN];unsigned char topCal;char stackOper[MAX_LEN];unsigned char topOper;/****************************************************************** 堆栈初始化*****************************************************************/void stackInit(void){int i;for(i=0;i<MAX_LEN;i++){stackCal[i].isOper = 0;stackCal[i].Num = 0;stackOper[i] = 0;}topCal = topOper = 0;}/***************************************************************** * 返回堆栈的栈顶,返回后栈顶减一*****************************************************************/ STRUCT_CAL * stackCalPop(void){if(topCal == 0)return (STRUCT_CAL *)0;return stackCal+(--topCal);}/***************************************************************** * 计算表达式入栈*****************************************************************/void stackCalPush(double num, unsigned char isOper){if(topCal>=MAX_LEN)return;stackCal[topCal].Num = num;stackCal[topCal].isOper= isOper;topCal++;}/***************************************************************** * 操作符出栈*****************************************************************/char stackOperPop(void){if(topOper == 0)return 0;return stackOper[--topOper];}/****************************************************************** 操作符入栈*****************************************************************/void stackOperPush(char oper){if(topOper >=MAX_LEN)return;stackOper[topOper++] = oper;}/****************************************************************** 比较两个sour sour1 的优先级* 1 sour >= sour1 直接入操作符栈* 0 sour < sour1 直接入计算表达式栈*****************************************************************/ unsigned char comparPrior(char sour, char sour1){if(sour =='\0' ||sour1 == '\0') return 1;switch(sour){case '+':case '-':if(sour1 == '*' ||sour1 == '/'||sour1 == '+' ||sour1 == '-' ){return 0;}else{return 1;}break;case '*':case '/':if(sour1 == '*' ||sour1 == '/'||sour1 == '+' ||sour1 == '-'||sour1 == '('){return 1;}else{return 0;}break;default:return 1;break;}}/****************************************************************** 将输入的字符串转换为栈*****************************************************************/void StrToCal(char *pStr){int tmpNum = 0;char tmpOper;char islastNum = 0;//判断上一个字符是什么。
C语言简易计算器的实现

C语言简易计算器的实现C语言简易计算器是一种用于进行基本数学运算的程序。
实现一个简易计算器的关键是要能够解析用户输入的数学表达式,并将其转化为计算机可以理解的形式,然后进行计算,并输出结果。
下面是一个大约1200字以上的示例实现。
```c#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <ctype.h>#define MAX_SIZE 100//定义操作符的优先级int getPriority(char op)if (op == '+' , op == '-')return 1;else if (op == '*' , op == '/')return 2;elsereturn 0;//进行四则运算int calculate(int a, int b, char op)switch (op)case '+': return a + b;case '-': return a - b;case '*': return a * b;case '/': return a / b;default: return 0;}//将中缀表达式转换为后缀表达式void infixToPostfix(char* infixExp, char* postfixExp) char stack[MAX_SIZE];int top = -1;int j = 0;for (int i = 0; infixExp[i] != '\0'; i++)if (isdigit(infixExp[i])) { // 数字直接输出到后缀表达式while (isdigit(infixExp[i]))postfixExp[j++] = infixExp[i++];}postfixExp[j++] = ' ';i--;}else if (infixExp[i] == '(') { // 左括号压入栈stack[++top] = infixExp[i];}else if (infixExp[i] == ')') { // 右括号弹出栈内所有操作符并输出到后缀表达式,直到遇到左括号while (top != -1 && stack[top] != '(')postfixExp[j++] = stack[top--];postfixExp[j++] = ' ';}top--; // 弹出栈顶的左括号}else { // 操作符while (top != -1 && getPriority(stack[top]) >=getPriority(infixExp[i]))postfixExp[j++] = stack[top--];postfixExp[j++] = ' ';stack[++top] = infixExp[i];}}while (top != -1) { // 将栈内剩余操作符弹出并输出到后缀表达式postfixExp[j++] = stack[top--];postfixExp[j++] = ' ';}postfixExp[j] = '\0';//计算后缀表达式的值int evaluatePostfix(char* postfixExp)char stack[MAX_SIZE];int top = -1;for (int i = 0; postfixExp[i] != '\0'; i++)if (isdigit(postfixExp[i])) { // 数字压入栈int num = 0;while (isdigit(postfixExp[i]))num = num * 10 + (postfixExp[i++] - '0');stack[++top] = num;i--;}else if (postfixExp[i] == ' ')continue;}else { // 操作符,弹出栈顶的两个数进行计算,并将结果压入栈int b = stack[top--];int a = stack[top--];int result = calculate(a, b, postfixExp[i]);stack[++top] = result;}}return stack[top];int maichar infixExp[MAX_SIZE];printf("请输入中缀表达式:");fgets(infixExp, sizeof(infixExp), stdin); // 读取用户输入//将中缀表达式转换为后缀表达式char postfixExp[MAX_SIZE];infixToPostfix(infixExp, postfixExp);printf("后缀表达式为:%s\n", postfixExp);//计算后缀表达式的值并输出int result = evaluatePostfix(postfixExp);printf("计算结果为:%d\n", result);return 0;```这个简易计算器的实现基于栈的数据结构。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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缺少右括号提示错误图五、遇到的问题及解决在编程的时候总是会有很多的意想不到的为题出现。