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;```这个简易计算器的实现基于栈的数据结构。
c语言基于二叉树的表达式求值算法
c语言基于二叉树的表达式求值算法C语言中,基于二叉树的表达式求值算法主要包括两部分:中缀表达式转换为后缀表达式和后缀表达式求值。
1.中缀表达式转换为后缀表达式中缀表达式是我们常见的数学表达方式,例如3 + 4 * 2 - 5。
为了方便计算机求值,我们需要将中缀表达式转换为后缀表达式,也叫做逆波兰表达式。
转换的过程使用栈数据结构来实现。
具体算法如下:1.定义一个栈和一个结果字符串,栈用于存储操作符,结果字符串用于保存后缀表达式。
2.从左到右遍历中缀表达式的每一个字符。
3.如果当前字符是数字,直接将其加入结果字符串。
4.如果当前字符是左括号"(",将其入栈。
5.如果当前字符是右括号")",则依次将栈顶的操作符弹出并加入结果字符串,直到遇到左括号为止,同时将左括号从栈中弹出。
6.如果当前字符是操作符,需要将栈中优先级比当前操作符高或者相等的操作符弹出并加入结果字符串,然后将当前操作符入栈。
7.遍历完所有字符后,将栈中剩余的操作符依次弹出并加入结果字符串。
8.最终结果字符串就是后缀表达式。
例如,对于中缀表达式3 + 4 * 2 - 5,转换为后缀表达式为3 4 2 * + 5 -2.后缀表达式求值后缀表达式求值算法使用栈数据结构来实现。
具体算法如下:1.定义一个栈,用于存储操作数。
2.从左到右遍历后缀表达式的每一个字符。
3.如果当前字符是数字,则将其转换为对应的整数并入栈。
4.如果当前字符是操作符,则从栈中弹出两个操作数,先弹出的作为右操作数,后弹出的作为左操作数,根据操作符进行运算,得到结果后入栈。
5.遍历完所有字符后,栈顶的数字即为最终的结果。
例如,对于后缀表达式3 4 2 * + 5 -,求值的过程如下:1.入栈3。
2.入栈4。
3.入栈2。
4.弹出2和4,计算4 * 2 = 8,将8入栈。
5.弹出8和3,计算3 + 8 = 11,将11入栈。
6.入栈5。
7.弹出5和11,计算11 - 5 = 6,得到最终结果。
C语言实现表达式计算
一、设计思想两种算法首先都要建立两个栈,一个是存放操作数的数栈OdStack,一个是存放运算符的符栈OpStack。
数栈采用double型的用来存放浮点数,符栈采用char型的用来存放运算符,由于考虑到运算符有优先级的问题,所以事先做了一个Type用来存储运算符的优先级。
栈建立好了之后做栈的相关操作,初始化栈,入栈,出栈,看栈顶。
其中入栈要判满,出栈和看栈顶要判空。
中缀转后缀再计算的算法。
此算法的基本思路是先将中缀表达式转换成后缀表达式,之后再利用后缀表达式的算法对表达式进行计算。
首先,用一个char数组将中缀表达式读入,对数组中的每一个元素进行处理,区分哪些是数,哪些是运算符。
如果是数元素(或小数点元素),则依次存入用来存储后缀表达式的char数组,直到一个整合数存完之后用空格将其与后面的元素分开。
如果是运算符元素,则根据当前运算符的优先级和栈里面的运算符的优先级进行处理。
如果栈内元素的优先级小于当前元素的优先级或者栈内为空,则将当前运算符入栈;如果栈内元素的优先级大于等于当前元素的,则依次将出栈元素存入后缀表达式,并用空格将其与后面的元素分开,直到栈内元素的优先级小或者栈内为空。
对于左括号来说,无条件进栈,并只在有右括号出现的时候才有可能出栈。
对于右括号来说,无条件让栈内元素出栈,直到左括号出栈。
依次将每个元素进行处理直到中缀表达式索引完毕。
至此,已经实现了将中缀表达式转换成了后缀表达式,在数组的最后加上结束符以便下一步的调用。
第二步,读出后缀表达式并进行计算。
如果索引到空格则将索引标志后推1位。
之后要先对char型的数字元素进行整合,从后缀表达式中依次取出数字元素(连同小数点)存入一个新的char型数组,直到一整个数取完后通过atof函数将char型转换成浮点型存入数栈,并将新数组初始化用来存储下一个数。
如果是索引到运算符,则在数栈中出栈两个数字与当前运算符进行运算,先出栈的数字放在运算符后面,后出栈的数字放在运算符的前面,将运算以后的结果再次存入数栈。
C语言简单计算器原理——表达式求值(采用逆波兰表达式和栈结合)
C语⾔简单计算器原理——表达式求值(采⽤逆波兰表达式和栈
结合)
表达式的求解的关键是将其转换成逆波兰表达式(即后缀表达式,如1+2*3它的逆波兰表达式为123*+),在后缀表达式中已经考虑了运算符的优先级,
没有括号,只有操作数和运算符。
算术表达式转换成后缀表达式⽅法如下:
依次从键盘输⼊表达式的字符ch,对于每个ch:
(1)若ch为数字则直接将其放⼊后缀数组exp中并以#号标记数值串结束。
(2)若ch为"(",则直接将其压⼊字符栈op中。
(3)若ch为")",则将栈中"("以前的字符依次全部删除并将其放⼊后缀数组exp中,然后再将字符ch放⼊字符栈op中。
(4)若ch为"+"."-",则将栈中"("以前的运算符依次全部删除并将其放⼊后缀数组exp中,然后再将ch放⼊op栈中。
(5)若ch为"*"."/",则将栈顶连续的"*"."/"删除,并放⼊后缀数组exp中,然后将ch放⼊op栈中。
(6)若字符串str扫描完毕,则将栈中所有运算符删除并放⼊后缀数组exp,最后在后缀数组exp中便可得到后缀表达式。
在对后缀表达式求值时要⽤到⼀个数值栈st,在后缀数组exp中从头开始扫描,若是数字则将其放⼊数值栈中,
若遇到字符就进⾏两次退栈,并将运算结果再放⼊栈中,如此重复下去,最后当后缀数组扫描完后数值栈st的栈顶元素便是所要求的表达式的值。
中缀、前缀、后缀表达式的运算
中缀、前缀、后缀表达式的运算 中缀表达式,就是在表达式中,操作符在操作数的中间,⽐如 (1+2)*3,+和*在1, 2, 3的中间。
前缀表达式,就是操作符在操作数的前⾯,⽐如 +12,+在1, 2的前⾯。
后缀表达式,就是操作符在操作数的后⾯,⽐如 12+,+在1, 2的后⾯。
为什么会有这么多表达式呢?它们⽬的不同。
中缀表达式,便于我们书写,也符合我们的阅读习惯,在计算机程序中,都是写中缀表达式,但它却不利于计算机进⾏算术计算,因为涉及到优先级和括号。
前缀表达式和后缀表达式中没有括号,并且运算符的优先级也通过它们在表达式中的顺序体现出来了,有利于计算机进⾏算术运算。
前缀表达式也叫波兰表达式,因为它是由⼀个波兰⼈发明的,相应的,后缀表达式也称为逆波兰表达式。
举个例⼦来说明⼀下三者的运算过程,假设计算(3+4)*5-6 使⽤中缀表达式进⾏计算 1,创建两个栈,⼀个是数字栈,⽤来存放操作数,⼀个是字符栈,⽤来存放操作符。
2,算术表达式是⼀个字符串,从左到右循环遍历表达式,依次取出每⼀个字符。
当取出的字符是操作数时,⼊数字栈。
当取出的字符是操作符时,这时还要看操作符的优先级和字符栈是否为空 如果字符栈为空,直接把取出的字符放⼊到字符栈中。
如果字符栈不为空,则要⽐较字符的优先级 如果取出的字符的优先级⼤于等于字符栈中栈顶的字符的优先级,直接把取出的字符放⼊到字符栈中。
如果取出的字符的优先级⽐字符栈中栈顶的字符的优先级低,则要循环进⾏如下操作,直到取出的字符的优先级⼤于等于字符栈中栈顶字符的优先级或者栈为空,此时,把取出的字符放⼊到字 符栈中。
如下操作就是: 1,从字符栈中弹出操作符 2,从数字栈中弹出两个操作数。
3,操作数结合操作符进⾏计算,要注意操作数顺序,后⾯pop出的数在求值的表达式中是前⾯的操作数,尤其是在做减法的时候 4,计算出的值放⼊到数字栈。
为什么要⽐较操作符的优先级呢?因为要确定操作数属于哪个操作符,相邻两个操作符之间的数字是共享的。
(完整版)数学表达式计算(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栈。
c语言中缀、后缀算术表达式求值用栈实现
c语言中缀、后缀算术表达式求值用栈实现下面是用栈实现中缀表达式求值的示例代码:#include <stdio.h>#include <stdlib.h>#include <ctype.h>#define MAX_STACK_SIZE 100typedef struct {int top;int data[MAX_STACK_SIZE];} Stack;void init(Stack *s) {s->top = -1;}int is_empty(Stack *s) {return s->top == -1;}int is_full(Stack *s) {return s->top == MAX_STACK_SIZE - 1;}void push(Stack *s, int x) {if (is_full(s)) {printf("Error: stack overflow\n");exit(EXIT_FAILURE);}s->data[++s->top] = x;}int pop(Stack *s) {if (is_empty(s)) {printf("Error: stack underflow\n");exit(EXIT_FAILURE);}return s->data[s->top--];}int peek(Stack *s) {if (is_empty(s)) {printf("Error: stack underflow\n");exit(EXIT_FAILURE);}return s->data[s->top];}int precedence(char op) {switch (op) {case '+':case '-':return 1;case '*':case '/':return 2;default:return 0;}}int evaluate(int op1, int op2, char op) {switch (op) {case '+':return op1 + op2;case '-':return op1 - op2;case '*':return op1 * op2;case '/':return op1 / op2;default:printf("Error: invalid operator\n");exit(EXIT_FAILURE);}}int evaluate_infix(char *expr) {Stack op_stack, val_stack;init(&op_stack);init(&val_stack);while (*expr != '\0') {if (isdigit(*expr)) {int val = 0;while (isdigit(*expr)) {val = val * 10 + (*expr - '0');expr++;}push(&val_stack, val);} else if (*expr == '+' || *expr == '-' || *expr == '*' || *expr == '/') {while (!is_empty(&op_stack) && precedence(peek(&op_stack)) >= precedence(*expr)) {int op2 = pop(&val_stack);int op1 = pop(&val_stack);char op = pop(&op_stack);push(&val_stack, evaluate(op1, op2, op));}push(&op_stack, *expr);expr++;} else if (*expr == '(') {push(&op_stack, '(');expr++;} else if (*expr == ')') {while (peek(&op_stack) != '(') {int op2 = pop(&val_stack);int op1 = pop(&val_stack);char op = pop(&op_stack);push(&val_stack, evaluate(op1, op2, op));}pop(&op_stack);expr++;} else {printf("Error: invalid character\n");exit(EXIT_FAILURE);}}while (!is_empty(&op_stack)) {int op2 = pop(&val_stack);int op1 = pop(&val_stack);char op = pop(&op_stack);push(&val_stack, evaluate(op1, op2, op));}return peek(&val_stack);}int main() {char expr[100];printf("Enter infix expression: ");scanf("%[^\n]", expr);printf("Result = %d\n", evaluate_infix(expr));return 0;}下面是用栈实现后缀表达式求值的示例代码:#include <stdio.h>#include <stdlib.h>#include <ctype.h>#define MAX_STACK_SIZE 100typedef struct {int top;int data[MAX_STACK_SIZE];} Stack;void init(Stack *s) {s->top = -1;}int is_empty(Stack *s) {return s->top == -1;}int is_full(Stack *s) {return s->top == MAX_STACK_SIZE - 1;}void push(Stack *s, int x) {if (is_full(s)) {printf("Error: stack overflow\n");exit(EXIT_FAILURE);}s->data[++s->top] = x;}int pop(Stack *s) {if (is_empty(s)) {printf("Error: stack underflow\n");exit(EXIT_FAILURE);}return s->data[s->top--];}int peek(Stack *s) {if (is_empty(s)) {printf("Error: stack underflow\n");exit(EXIT_FAILURE);}return s->data[s->top];}int evaluate(int op1, int op2, char op) {switch (op) {case '+':return op1 + op2;case '-':return op1 - op2;case '*':return op1 * op2;case '/':return op1 / op2;default:printf("Error: invalid operator\n");exit(EXIT_FAILURE);}}int evaluate_postfix(char *expr) {Stack stack;init(&stack);while (*expr != '\0') {if (isdigit(*expr)) {int val = 0;while (isdigit(*expr)) {val = val * 10 + (*expr - '0');expr++;}push(&stack, val);} else if (*expr == '+' || *expr == '-' || *expr == '*' || *expr == '/') { int op2 = pop(&stack);int op1 = pop(&stack);push(&stack, evaluate(op1, op2, *expr));expr++;} else {printf("Error: invalid character\n");exit(EXIT_FAILURE);}}return peek(&stack);}int main() {char expr[100];printf("Enter postfix expression: ");scanf("%[^\n]", expr);printf("Result = %d\n", evaluate_postfix(expr));return 0;}。
c语言后缀表达式计算
c语言后缀表达式计算C语言是一门面向过程的编程语言,它能够处理各种不同的计算需求,包括后缀表达式的计算。
所谓后缀表达式,也叫做逆波兰表达式,是一种使用后缀符号(如“+”、“-”、“*”、“/”等)表示数学表达式的方法。
与中缀表达式相比,后缀表达式的计算更加高效和简单。
下面,我们就来一步步介绍C语言如何计算后缀表达式。
步骤一:将后缀表达式转换为栈要实现后缀表达式的计算,首先需要将后缀表达式对应的字符串转换为栈。
在这个过程中,需要分别处理操作数和操作符。
对于操作数,可以使用变量num来保存其值,并将其推入栈中。
对于操作符,可以利用switch语句来处理,如果遇到“+”或“-”或“*”或“/”等操作符,则需要从栈中弹出两个操作数进行计算,并将结果推入栈中。
示例代码如下:```c#include <stdio.h>#include <string.h>#include <stdlib.h>#define MAX_STACK_SIZE 100double stack[MAX_STACK_SIZE];int top = -1;void push(double num) {if (top >= MAX_STACK_SIZE - 1) {printf("Stack overflow.\n");return;}stack[++top] = num;}double pop() {if (top < 0) {printf("Stack underflow.\n");return 0;}return stack[top--];}int isOperator(char *token) {return (strcmp(token, "+") == 0 || strcmp(token, "-") == 0 ||strcmp(token, "*") == 0 || strcmp(token, "/") == 0);}void calculate(char *operator) {double num1 = pop();double num2 = pop();double result;switch (operator[0]) {case '+':result = num2 + num1;break;case '-':result = num2 - num1;break;case '*':result = num2 * num1;break;case '/':result = num2 / num1;break;}push(result);}int main() {char expression[100];printf("Enter the expression: ");gets(expression);char *token = strtok(expression, " ");while (token != NULL) {if (!isOperator(token)) {push(atof(token));} else {calculate(token);}token = strtok(NULL, " ");}printf("Result: %lf\n", pop());return 0;}```步骤二:读入后缀表达式完成栈的转换之后,就可以开始读入后缀表达式了。
后缀式计算过程
后缀式计算过程
嘿,朋友们!今天咱就来讲讲这后缀式计算过程。
啥是后缀式呢?简单来说,就是一种特别的计算表达方式。
咱平常做算术,都是先加减后乘除对吧,但后缀式可不一样。
就好比咱去超市买东西排队结账。
平常的计算方式就像是大家按先来后到排队,一个一个来。
而后缀式呢,就像是把这些商品和计算符号都扔到一个大框里,最后再一起算。
比如说,平常我们算 3 加 5 乘 2,得先算 5 乘 2 等于 10,再加上 3 得13。
但后缀式呢,就变成了3 5 2 * +。
先把3、5、2 放进去,看到乘号就先算 5 乘 2,得到 10,再看到加号,就把 3 和 10 加起来,还是13。
这可有意思了吧!那后缀式有啥好处呢?它能让计算更清晰,不容易出错呀。
我记得有一次,我给小侄子辅导数学作业,那算式写得密密麻麻,他看得晕头转向。
我就想,要是用后缀式,不就简单多了嘛。
于是我给他讲了后缀式,嘿,他一下子就明白了。
再比如说,我们在电脑编程里也常用到后缀式呢。
电脑可不像咱人脑,它得按照特定的规则来计算。
而后缀式就能让电脑的计算更准确、更高效。
其实呀,这后缀式就像一把特别的钥匙,能打开计算世界里的一扇新门。
让我们能从不同的角度去看计算,发现它的奇妙之处。
在生活中,我们也可以多试试用后缀式的思维去想问题。
有时候,换个角度,也许就能找到新的解决办法。
所以呀,朋友们,不妨多了解了解这后缀式计算过程,说不定哪天就能派上大用场呢!它能让我们的计算变得更有趣、更轻松。
试试吧,你会发现一个不一样的计算天地!。
编译原理——前缀后缀表达式
top--;
}
i--; //7)假如输入还未完毕,跳转到步骤2。
}
while(top!=0) //8)假如输入完毕,栈中剩余的所有操作符出栈并加到输出串中。
{
output[j++]=stack[top];
top--;
}
}
int main()
{ char input[50],output[50]="";
6假如是开括号栈中运算符逐个出栈并输出直到遇到闭括号
输入一个中缀表达式转换为后缀和前缀,并求值C程序
待修改……
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#define max 100
char ex[max]; /*存储后缀表达式*/
{
if(op=='+'||op=='-'||op=='*'||op=='/')
return true;
else
return false;
}
void convert(char *s,char *output) //将一个中缀串转换为后缀串,
{ int j=0;
strcpy(output,""); //输出串
while(stack[top]=='*'||stack[top]=='/')
{
ex[t]=stack[top];top--;t++;
}
- 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缺少右括号提示错误图五、遇到的问题及解决在编程的时候总是会有很多的意想不到的为题出现。