900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 中缀/后缀/前缀表达式及相互转换的手算详细步骤及C代码实现

中缀/后缀/前缀表达式及相互转换的手算详细步骤及C代码实现

时间:2022-06-24 03:25:04

相关推荐

中缀/后缀/前缀表达式及相互转换的手算详细步骤及C代码实现

文章目录

1 三种算术表达式2 后缀表达式相关考点2.1 中缀表达式转后缀表达式2.1.1 手算2.1.2 机算2.2 后缀表达式求值2.2.1 手算2.2.2 机算2.3 后缀表达式转中缀表达式2.3.1 手算2.3.2 机算3 前缀表达式相关考点3.1 中缀表达式转前缀表达式3.1.1 手算3.1.2 机算3.2 前缀表达式求值3.2.1 手算3.2.2 机算3.3 前缀表达式转中缀表达式3.3.1 手算3.3.2 机算

1 三种算术表达式

算术表达式由三个部分组成:操作数、运算符、界限符。界限符是必不可少的,也就是括号。括号或者说界限符反映了计算或者说运算符作用的先后顺序。但是有一个波兰数学家想这样做:可以不用界限符也能无歧义地表达运算顺序。于是发明了:① 逆波兰表达式,即后缀表达式;② 波兰表达式,即前缀表达式。

2 后缀表达式相关考点

2.1 中缀表达式转后缀表达式

2.1.1 手算

中缀转后缀的手算步骤:

① 确定中缀表达式中各个运算符的运算顺序,但是有时候运算顺序不唯一,因此对应的后缀表达式也不唯一。为了保证手算和机算结果相同,且保证运算顺序唯一,请遵从“左优先”原则:只要左边的运算符能先计算,就优先算左边的。确定完运算符的运算顺序后,如果有界限符即括号,就可以去掉全部的括号了,或者说可以忽略括号的存在继续下面步骤;

② 选择下一个运算符,按照【左操作数 右操作数 运算符】的方式组合成一个新的式子,然后放在原来操作符的位置。如果还有运算符没被处理,就继续②,否则最后得到的式子就是最终结果。下面是一个示例:

2.1.2 机算

实现中缀表达式转后缀表达式的逻辑过程:初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。从左到右扫描中缀表达式的各个字符,直到末尾。在扫描时可能遇到三种情况:

① 当前字符是数字:直接加入后缀表达式,然后处理下一个字符;

② 当前字符是括号,又分为两种情况:

1)当前字符是左括号即(则直接将当前字符入栈,然后处理下一个字符;2)当前字符是右括号即):若栈空则直接处理下一个字符。若栈非空则不断弹出栈顶元素——若弹出左括号(后则停止继续弹出(注意这个左括号(不加入后缀表达式)并直接处理下一个字符,否则将栈顶元素加入后缀表达式,然后继续弹出栈顶元素;

③ 当前字符是运算符,又分为两种情况:

1)栈空则直接把当前字符入栈,然后处理下一个字符;2)栈非空则不断弹出栈顶元素:若栈顶元素是左括号(或优先级低于当前字符的运算符则停止栈顶元素的弹出,再将栈顶元素再次入栈,之后再把当前字符入栈,然后处理下一个字符。若栈顶元素是运算符且优先级高于或等于当前字符,则将栈顶元素加入后缀表达式,然后继续弹出栈顶元素;

按上述方法处理完所有字符后,若栈非空则将栈中剩余字符依次弹出并依次加入后缀表达式。最后得到的表达式就是最终结果。示例代码如下:

//本程序只能处理有关运算符+、-、*、/的中缀表达式,不能是÷或者×及其他运算//界限符只能是英文状态的左右括号即'('、')',操作数只能是整数//本程序不会检查输入的中缀表达式是否正确,因此请您核验好自己的式子是否正确#include<stdio.h>#include<string.h> //strlen的头文件,用于判断字符串长度#include<stdlib.h> //malloc、free的头文件#define size 50//假定要转换的中缀表达式的字符数在50个以内typedef struct Linknode{//定义链栈及结点char data; //数据域struct Linknode *next; //指针域}*LiStack;bool InitStack(LiStack &S){//链栈的初始化,不带头结点S=NULL; //刚开始没有结点return true;}bool StackEmpty(LiStack S){//判断栈空return S==NULL;}bool Push(LiStack &S,char x){//将元素x入栈Linknode *s=(Linknode *)malloc(sizeof(Linknode)); //创建新结点if(s==NULL) //内存不足,创建失败return false;s->data=x;s->next=S; //将结点s作为链栈的栈顶结点S=s; //栈顶指针S指向结点sreturn true;}bool Pop(LiStack &S,char &x){//栈顶元素出栈,将值赋给xif(S==NULL)return false; //栈空则返回NULLx=S->data;Linknode *p=S;S=S->next;free(p);return true;}int main(){char temp,a[size],b[size]; //静态数组a、b分别存放要转换的中缀表达式和转换后的后缀表达式,字符变量temp存放弹出的栈顶元素scanf("%s",&a); //需要您输入中缀表达式LiStack S;//初始化一个栈,用于保存括号和暂时还不能确定运算顺序的运算符InitStack(S); //初始化链栈int i,j,length=strlen(a); //length为输入的中缀表达式的总长度,i、j分别为静态数组a、b的索引下标for(i=j=0;i<length;i++){if(a[i]>=48 && a[i]<=57){//若当前字符是数字,字符0-9的ACSII码范围是[48,57]b[j++]=a[i];if(a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/') //若下一个字符是运算符,即+、-、*、/,则b加一个空格,以免不同的操作数混在一起b[j++]=' ';}else if(a[i]=='(')Push(S,a[i]); //若当前字符是左括号则直接入栈else if(a[i]==')'){//若当前字符是右括号while(StackEmpty(S)==0){//栈非空则不断弹出栈内字符并加入后缀表达式Pop(S,temp);if(temp=='(') //直到弹出左括号停止,注意这个(不加入后缀表达式break;b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}}else switch(a[i]){//若当前字符是运算符case '*': case '/':{while(StackEmpty(S)==0){//若栈非空,则弹出栈中优先级高于或等于当前运算符的所有运算符,并将这些运算符加入后缀表达式Pop(S,temp);if(temp=='/'||temp=='*'){b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}else if(temp=='('||temp=='-'||temp=='+'){//若栈顶元素是左括号或者是优先级低于当前字符的运算符,则将栈顶元素入栈Push(S,temp);break;}}Push(S,a[i]); //把当前字符入栈break;}case '-': case '+':{while(StackEmpty(S)==0){//若栈非空,则弹出栈中优先级高于或等于当前运算符的所有运算符,并将这些运算符加入后缀表达式Pop(S,temp);if(temp=='('){//若栈顶元素是左括号,则将栈顶元素入栈Push(S,temp);break;}else if(temp=='/'||temp=='*'||temp=='-'||temp=='+'){b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}}Push(S,a[i]); //把当前字符入栈break;}}}while(StackEmpty(S)==0){//栈非空时依次弹出栈顶元素并加入后缀表达式Pop(S,temp);b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}printf("结果是:\n");for(i=0;i<j;i++) //j是数组中下一个可以插入元素的位置下标,因此b中存放字符的索引区间为[0,j-1]printf("%c",b[i]); //输出b中的元素printf("\n");return 0;}

运行程序后需要输入待转换的中缀表达式,下面是三个输入输出示例:

2.2 后缀表达式求值

2.2.1 手算

后缀表达式求值的手算步骤:从左往右扫描后缀表达式的每一个字符,每遇到一个运算符,就选择运算符左面距离最近的两个操作数执行对应运算,执行运算时注意两个操作数的左右顺序,得到计算结果后去掉刚刚的两个操作数,将新得到的计算结果放在刚刚的这个运算符的位置并代替之,继续从左到右扫描字符直到扫描完全部字符。扫描结束最后得到的就是最终结果。下面是一个示例:

2.2.2 机算

需要初始化一个栈,用于存放当前暂时还不能确定运算次序的操作数。用栈实现后缀表达式求值的逻辑过程:

① 从左往右扫描后缀表达式的每一个字符,直到扫描完所有字符;

② 若扫描到的字符是操作数则压入栈,并回到①,否则执行③;

③ 若扫描到的字符是运算符,则连续弹出两个栈顶元素(注意:先出栈的是“右操作数”),然后对这两个操作数执行相应运算,然后再将运算结果入栈,回到①。

若被扫描的后缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果。示例代码如下:

//本程序只能处理有关运算符+、-、*、/的后缀表达式,不能是÷或者×及其他运算//本程序不会检查输入的后缀表达式是否正确,因此请您核验好自己的式子是否正确//操作数长度在10位以内且必须是整数//请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开#include<stdio.h>#include<math.h> //pow的头文件,用于求乘方数#include<string.h> //strlen的头文件,用于判断字符串长度#include<stdlib.h> //malloc、free的头文件#define size 50//假定要求值的后缀表达式的字符数在50个以内#define num_length 10 //假定后缀表达式中的每一个操作数最长为10位数typedef struct Linknode{//定义链栈及结点float data; //数据域struct Linknode *next; //指针域}*LiStack;bool InitStack(LiStack &S){//链栈的初始化,不带头结点S=NULL; //刚开始没有结点return true;}bool Push(LiStack &S,float x){//将元素x入栈Linknode *s=(Linknode *)malloc(sizeof(Linknode)); //创建新结点if(s==NULL) //内存不足,创建失败return false;s->data=x;s->next=S; //将结点s作为链栈的栈顶结点S=s; //栈顶指针S指向结点sreturn true;}bool Pop(LiStack &S,float &x){//栈顶元素出栈,将值赋给xif(S==NULL)return false; //栈空则返回NULLx=S->data;Linknode *p=S;S=S->next;free(p);return true;}int main(){char a[size]; //静态数组a存放要处理的后缀表达式float right,left,tmp=0; //right,left为弹出栈的元素,依次为右操作数和左操作数int b[num_length];//静态数组b存放操作数的各位数字如231的2、3、1scanf("%s",&a); //需要您输入后缀表达式LiStack S;//初始化一个栈,用于存放当前暂时还不能确定运算次序的操作数InitStack(S); //初始化链栈int i,j=0,length=strlen(a); //length为输入的后缀表达式的总长度,i、j分别为静态数组a、b的索引下标for(i=0;i<length;i++){if(a[i]>=48 && a[i]<=57){//若当前字符是数字,字符0-9的ACSII码范围是[48,57]b[j++]=a[i]-48; //字符型的数字减去48就是数字本身,如ASCII码为51的字符为"3",而"3"-48=51-48=3就是数字3本身if(a[i+1]==','||a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/'){//若下一个字符是逗号或者运算符,则代表凑够一个操作数了int m=j;for(int k=0;k<m;k++) // 将分散的各位数字组成一个操作数tmp+=b[k]*int(pow(10,--j));Push(S,tmp); //将当前操作数入栈tmp=0; //在遇到下一个操作数之前将tmp值归零}}else switch(a[i]){//若当前字符是运算符case '*': case '/': case '-': case '+':{Pop(S,right); //先出栈的是“右操作数”Pop(S,left); //后出栈的是“左操作数”if(a[i]=='+')Push(S,left+right); //执行运算之后将结果入栈,下面三个也是这样else if(a[i]=='-')Push(S,left-right);else if(a[i]=='*')Push(S,left*right);else if(a[i]=='/')Push(S,left/right);}}}Pop(S,tmp); //若被扫描的后缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果printf("结果是:%.2f\n",tmp); //输出结果return 0;}

运行程序后需要输入待求值的后缀表达式,注意本程序只能处理有关运算符+、-、*、/的后缀表达式,不能是÷或者×及其他运算,本程序不会检查输入的后缀表达式是否正确,因此请您核验好自己的式子是否正确,操作数长度在10位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

2.3 后缀表达式转中缀表达式

2.3.1 手算

后缀表达式转换成中缀表达式的手算步骤:从左往右扫描后缀表达式的每一个字符,每遇到一个运算符,就选择运算符左面距离最近的两个操作数,将【左操作数 右操作数 运算符】变为(左操作数 运算符 右操作数)的形式。注意两个操作数的左右顺序,得到一个式子后去掉刚刚的两个操作数,将得到的式子放在刚刚的这个运算符的位置并代替之,继续从左到右扫描字符直到扫描完全部字符。扫描结束最后得到的式子就是最终结果。下面是一个示例:

2.3.2 机算

需要初始化一个栈,用于存放当前暂时还不能确定运算次序的操作数。用栈实现后缀表达式转中缀表达式的逻辑过程:

① 从左往右扫描下一个元素,直到处理完所有元素;

② 若扫描到操作数则压入栈,并回到①,否则执行③;

③ 若扫描到运算符,则弹出两个栈顶元素(注意:先出栈的是“右操作数”),构成(左操作数 运算符 右操作数),然后将其压回栈顶,回到①。

若被扫描的后缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果。示例代码如下:

//本程序只能处理有关运算符+、-、*、/的后缀表达式,不能是÷或者×及其他运算//本程序不会检查输入的后缀表达式是否正确,因此请您核验好自己的式子是否正确//操作数长度在10位以内且必须是整数//请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开#include<stdio.h>#include<string.h> //strlen的头文件,用于判断字符串长度#include<stdlib.h> //malloc、free的头文件#define size 50//假定输入的后缀表达式的字符数在50以内#define num_length 10 //假定每一个操作数最长为10位数typedef struct Linknode{//定义链栈及结点char data[size]; //数据域struct Linknode *next; //指针域}*LiStack;bool InitStack(LiStack &S){//链栈的初始化,不带头结点S=NULL; //刚开始没有结点return true;}bool Push(LiStack &S,char *x){//将元素x入栈Linknode *s=(Linknode *)malloc(sizeof(Linknode)); //创建新结点if(s==NULL||strlen(x)>size) //内存不足或者长度超过size,则失败return false;int i;for(i=0;i<strlen(x);i++)s->data[i]=x[i];s->data[i]='\0';s->next=S; //将结点s作为栈顶结点S=s; //栈顶指针S指向结点sreturn true;}bool Pop(LiStack &S,char *x){//栈顶元素出栈,将值赋给xif(S==NULL)return false; //栈空则返回NULLLinknode *p=S; //p指向栈顶结点int i;for(i=0;p->data[i]!='\0';i++)x[i]=p->data[i];x[i]='\0';S=p->next;free(p);return true;}int main(){char a[size]; //静态数组a存放要处理的后缀表达式char right[size],left[size]; //right,left为弹出栈的元素,依次为右操作数和左操作数char b[num_length];//静态数组b存放操作数的各位数字如231的'2'、'3'、'1'scanf("%s",&a); //需要您输入后缀表达式LiStack S;//初始化一个栈,用于存放当前暂时还不能确定运算次序的字符串形式的操作数InitStack(S); //初始化链栈int i,j=0,length=strlen(a); //length为输入的后缀表达式的总长度,i、j分别为静态数组a、b的索引下标for(i=0;i<length;i++){if(a[i]>=48&&a[i]<=57){//若当前字符是数字,字符0-9的ACSII码范围是[48,57]b[j++]=a[i];if(a[i+1]==','||a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/'){//若下一个字符是逗号或者运算符,则代表凑够一个操作数了b[j]='\0';Push(S,b); //将当前操作数入栈j=0; //将j归零}}else switch(a[i]){case '*': case '/': case '-': case '+':{//若当前字符是运算符Pop(S,right); //先出栈的是“右操作数”Pop(S,left); //后出栈的是“左操作数”if(strlen(left)+strlen(right)+1+2>size) // 左右操作数长度之和再加上操作符、左右括号的长度过长,容不下return false;char tmp[size]; //临时变量tmp[0]='('; //先存左括号int k;for(k=0;k<strlen(left);k++)tmp[k+1]=left[k]; //存左操作数tmp[strlen(left)+1]=a[i]; //存运算符for(k=0;k<strlen(right);k++)tmp[k+strlen(left)+2]=right[k]; //存右操作数tmp[strlen(left)+strlen(right)+2]=')'; //最后存右括号tmp[strlen(left)+strlen(right)+3]='\0';Push(S,tmp); //将结果入栈}}}char c[size];Pop(S,c); //若被扫描的后缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果printf("结果是:%s\n",c); //输出结果return 0;}

运行程序后需要输入待转换的后缀表达式,注意本程序只能处理有关运算符+、-、*、/的后缀表达式,不能是÷或者×及其他运算,本程序不会检查输入的后缀表达式是否正确,因此请您核验好自己的式子是否正确,操作数长度在10位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

3 前缀表达式相关考点

3.1 中缀表达式转前缀表达式

3.1.1 手算

中缀转前缀的手算步骤:

① 确定中缀表达式中各个运算符的运算顺序,但是有时候运算顺序不唯一,因此对应的前缀表达式也不唯一。为了保证手算和机算结果相同,且保证运算顺序唯一,请遵从“右优先”原则:只要右边的运算符能先计算,就优先算右边的。确定完运算符的运算顺序后,如果有界限符即括号,就可以去掉全部的括号了,或者说可以忽略括号的存在继续下面步骤;

② 选择下一个运算符,按照【运算符 左操作数 右操作数】的方式组合成一个新的式子,然后放在原来操作符的位置。如果还有运算符没被处理,就继续②,否则最后得到的式子就是最终结果。下面是一个示例:

3.1.2 机算

实现中缀表达式转前缀表达式的逻辑过程:初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。从右到左扫描中缀表达式的各个字符,直到末尾。在扫描时可能遇到三种情况:

① 当前字符是数字:直接加入前缀表达式,然后处理下一个字符;

② 当前字符是括号,又分为两种情况:

1)当前字符是右括号即)则直接将当前字符入栈,然后处理下一个字符;2)当前字符是左括号即(:若栈空则直接处理下一个字符。若栈非空则不断弹出栈顶元素——若弹出右括号)后则停止继续弹出(注意这个右括号)不加入前缀表达式)并直接处理下一个字符,否则将栈顶元素加入前缀表达式,然后继续弹出栈顶元素;

③ 当前字符是运算符,又分为两种情况:

1)栈空则直接把当前字符入栈,然后处理下一个字符;2)栈非空则不断弹出栈顶元素:若栈顶元素是右括号)或优先级高于当前字符的运算符则停止栈顶元素的弹出,再将栈顶元素再次入栈,之后再把当前字符入栈,然后处理下一个字符。若栈顶元素是运算符且优先级低于或等于当前字符,则将栈顶元素加入前缀表达式,然后继续弹出栈顶元素;

按上述方法处理完所有字符后,若栈非空则将栈中剩余字符依次弹出并依次加入前缀表达式。将最后得到的前缀表达式倒置就是最终结果。示例代码如下:

//本程序只能处理有关运算符+、-、*、/的中缀表达式,不能是÷或者×及其他运算//界限符只能是英文状态的左右括号即'('、')',操作数只能是整数//本程序不会检查输入的中缀表达式是否正确,因此请您核验好自己的式子是否正确#include<stdio.h>#include<string.h> //strlen的头文件,用于判断字符串长度#include<stdlib.h> //malloc、free的头文件#define size 50//假定要转换的中缀表达式的字符数在50个以内typedef struct Linknode{//定义链栈及结点char data; //数据域struct Linknode *next; //指针域}*LiStack;bool InitStack(LiStack &S){//链栈的初始化,不带头结点S=NULL; //刚开始没有结点return true;}bool StackEmpty(LiStack S){//判断栈空return S==NULL;}bool Push(LiStack &S,char x){//将元素x入栈Linknode *s=(Linknode *)malloc(sizeof(Linknode)); //创建新结点if(s==NULL) //内存不足,创建失败return false;s->data=x;s->next=S; //将结点s作为链栈的栈顶结点S=s; //栈顶指针S指向结点sreturn true;}bool Pop(LiStack &S,char &x){//栈顶元素出栈,将值赋给xif(S==NULL)return false; //栈空则返回NULLx=S->data;Linknode *p=S;S=S->next;free(p);return true;}int main(){char temp,a[size],b[size]; //静态数组a、b分别存放要转换的中缀表达式和转换后的前缀表达式,字符变量temp存放弹出的栈顶元素scanf("%s",&a); //需要您输入中缀表达式LiStack S;//初始化一个栈,用于保存括号和暂时还不能确定运算顺序的运算符InitStack(S); //初始化链栈int i,j,length=strlen(a); //length为输入的中缀表达式的总长度,i、j分别为静态数组a、b的索引下标for(i=length-1,j=0;i>=0;i--){//从右到左扫描中缀表达式的各个字符,直到末尾if(a[i]>=48 && a[i]<=57){//若当前字符是数字,字符0-9的ACSII码范围是[48,57]b[j++]=a[i];if(a[i-1]=='+'||a[i-1]=='-'||a[i-1]=='*'||a[i-1]=='/') //若上一个字符是运算符,即+、-、*、/,则b加一个空格,以免不同的操作数混在一起b[j++]=' ';}else if(a[i]==')')Push(S,a[i]); //若当前字符是右括号则直接入栈else if(a[i]=='('){//若当前字符是左括号while(StackEmpty(S)==0){//栈非空则不断弹出栈内字符并加入前缀表达式Pop(S,temp);if(temp==')') //直到弹出右括号停止,注意这个)不加入前缀表达式break;b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}}else switch(a[i]){//若当前字符是运算符case '*': case '/':{while(StackEmpty(S)==0){//若栈非空,则弹出栈中优先级低于或等于当前运算符的所有运算符,并将这些运算符加入前缀表达式Pop(S,temp);if(temp=='+'||temp=='-'||temp=='/'||temp=='*'){b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}else if(temp==')'){//若栈顶元素是右括号或者是优先级高于当前字符的运算符,则将栈顶元素入栈Push(S,temp);break;}}Push(S,a[i]); //把当前字符入栈break;}case '-': case '+':{while(StackEmpty(S)==0){//若栈非空,则弹出栈中优先级低于或等于当前运算符的所有运算符,并将这些运算符加入前缀表达式Pop(S,temp);if(temp==')'||temp=='*'||temp=='/'){//若栈顶元素是右括号或者是优先级高于当前字符的运算符,则将栈顶元素入栈Push(S,temp);break;}else if(temp=='+'||temp=='-'){b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}}Push(S,a[i]); //把当前字符入栈break;}}}while(StackEmpty(S)==0){//栈非空时依次弹出栈顶元素并加入前缀表达式Pop(S,temp);b[j++]=temp;b[j++]=' '; //加一个空格,从而将字符隔开}printf("结果是:\n");for(i=j-1;i>=0;i--) //b中存放字符的索引区间为[0,j-1]printf("%c",b[i]); //倒序输出b中的元素printf("\n");return 0;}

运行程序后需要输入待转换的中缀表达式,下面是三个输入输出示例:

3.2 前缀表达式求值

3.2.1 手算

前缀表达式求值的手算步骤:从右往左扫描前缀表达式的每一个字符,每遇到一个运算符,就选择运算符右面距离最近的两个操作数执行对应运算,执行运算时注意两个操作数的左右顺序,得到计算结果后去掉刚刚的两个操作数,将新得到的计算结果放在刚刚的这个运算符的位置并代替之,继续从右到左扫描字符直到扫描完全部字符。扫描结束最后得到的就是最终结果。下面是一个示例:

3.2.2 机算

需要初始化一个栈,用于存放当前暂时还不能确定运算次序的操作数。用栈实现前缀表达式求值的逻辑过程:

① 从右往左扫描前缀表达式的每一个字符,直到扫描完所有字符;

② 若扫描到的字符是操作数则压入栈,并回到①,否则执行③;

③ 若扫描到的字符是运算符,则连续弹出两个栈顶元素(注意:先出栈的是“左操作数”),然后对这两个操作数执行相应运算,然后再将运算结果入栈,回到①。

若被扫描的前缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果。示例代码如下:

//本程序只能处理有关运算符+、-、*、/的前缀表达式,不能是÷或者×及其他运算//本程序不会检查输入的前缀表达式是否正确,因此请您核验好自己的式子是否正确//操作数长度在10位以内且必须是整数//请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开#include<stdio.h>#include<math.h> //pow的头文件,用于求乘方数#include<string.h> //strlen的头文件,用于判断字符串长度#include<stdlib.h> //malloc、free的头文件#define size 50//假定要求值的前缀表达式的字符数在50个以内#define num_length 10 //假定前缀表达式中的每一个操作数最长为10位数typedef struct Linknode{//定义链栈及结点float data; //数据域struct Linknode *next; //指针域}*LiStack;bool InitStack(LiStack &S){//链栈的初始化,不带头结点S=NULL; //刚开始没有结点return true;}bool Push(LiStack &S,float x){//将元素x入栈Linknode *s=(Linknode *)malloc(sizeof(Linknode)); //创建新结点if(s==NULL) //内存不足,创建失败return false;s->data=x;s->next=S; //将结点s作为链栈的栈顶结点S=s; //栈顶指针S指向结点sreturn true;}bool Pop(LiStack &S,float &x){//栈顶元素出栈,将值赋给xif(S==NULL)return false; //栈空则返回NULLx=S->data;Linknode *p=S;S=S->next;free(p);return true;}int main(){char a[size]; //静态数组a存放要处理的前缀表达式float right,left,tmp=0; //right,left为弹出栈的元素,依次为右操作数和左操作数int b[num_length];//静态数组b存放操作数的各位数字如231的2、3、1scanf("%s",&a); //需要您输入前缀表达式LiStack S;//初始化一个栈,用于存放当前暂时还不能确定运算次序的操作数InitStack(S); //初始化链栈int i,j=0,length=strlen(a); //length为输入的前缀表达式的总长度,i、j分别为静态数组a、b的索引下标for(i=length-1;i>=0;i--){//从右到左扫描if(a[i]>=48 && a[i]<=57){//若当前字符是数字,字符0-9的ACSII码范围是[48,57]b[j++]=a[i]-48; //字符型的数字减去48就是数字本身,如ASCII码为51的字符为"3",而"3"-48=51-48=3就是数字3本身if(a[i-1]==','||a[i-1]=='+'||a[i-1]=='-'||a[i-1]=='*'||a[i-1]=='/'){//若上一个字符是逗号或者运算符,则代表凑够一个操作数了int m=j;for(int k=0;k<m;k++) // 将分散的各位数字组成一个操作数tmp+=b[k]*int(pow(10,k));Push(S,tmp); //将当前操作数入栈tmp=0; //在遇到下一个操作数之前将tmp值归零j=0;}}else switch(a[i]){//若当前字符是运算符case '*': case '/': case '-': case '+':{Pop(S,left); //先出栈的是“左操作数”Pop(S,right); //后出栈的是“右操作数”if(a[i]=='+')Push(S,left+right); //执行运算之后将结果入栈,下面三个也是这样else if(a[i]=='-')Push(S,left-right);else if(a[i]=='*')Push(S,left*right);else if(a[i]=='/')Push(S,left/right);}}}Pop(S,tmp); //若被扫描的前缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果printf("结果是:%.2f\n",tmp); //输出结果return 0;}

运行程序后需要输入待求值的前缀表达式,注意本程序只能处理有关运算符+、-、*、/的前缀表达式,不能是÷或者×及其他运算,本程序不会检查输入的前缀表达式是否正确,因此请您核验好自己的式子是否正确,操作数长度在10位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

3.3 前缀表达式转中缀表达式

3.3.1 手算

前缀表达式转换成中缀表达式的手算步骤:从右往左扫描前缀表达式的每一个字符,每遇到一个运算符,就选择运算符右面距离最近的两个操作数,将【运算符 左操作数 右操作数】变为(左操作数 运算符 右操作数)的形式。注意两个操作数的左右顺序,得到一个式子后去掉刚刚的两个操作数,将得到的式子放在刚刚的这个运算符的位置并代替之,继续从右到左扫描字符直到扫描完全部字符。扫描结束最后得到的式子就是最终结果。下面是一个示例:

3.3.2 机算

需要初始化一个栈,用于存放当前暂时还不能确定运算次序的操作数。用栈实现前缀表达式转中缀表达式的逻辑过程:

① 从右往左扫描下一个元素,直到处理完所有元素;

② 若扫描到操作数则压入栈,并回到①,否则执行③;

③ 若扫描到运算符,则弹出两个栈顶元素(注意:先出栈的是“左操作数”),构成(左操作数 运算符 右操作数),然后将其压回栈顶,回到①。

若被扫描的前缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果。示例代码如下:

//本程序只能处理有关运算符+、-、*、/的前缀表达式,不能是÷或者×及其他运算//本程序不会检查输入的前缀表达式是否正确,因此请您核验好自己的式子是否正确//操作数长度在10位以内且必须是整数//请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开#include<stdio.h>#include<string.h> //strlen的头文件,用于判断字符串长度#include<stdlib.h> //malloc、free的头文件#define size 50//假定输入的前缀表达式的字符数在50以内#define num_length 10 //假定每一个操作数最长为10位数typedef struct Linknode{//定义链栈及结点char data[size]; //数据域struct Linknode *next; //指针域}*LiStack;bool InitStack(LiStack &S){//链栈的初始化,不带头结点S=NULL; //刚开始没有结点return true;}bool Push(LiStack &S,char *x){//将元素x入栈Linknode *s=(Linknode *)malloc(sizeof(Linknode)); //创建新结点if(s==NULL||strlen(x)>size) //内存不足或者长度超过size,则失败return false;int i;for(i=0;i<strlen(x);i++)s->data[i]=x[i];s->data[i]='\0';s->next=S; //将结点s作为栈顶结点S=s; //栈顶指针S指向结点sreturn true;}bool Pop(LiStack &S,char *x){//栈顶元素出栈,将值赋给xif(S==NULL)return false; //栈空则返回NULLLinknode *p=S; //p指向栈顶结点int i;for(i=0;p->data[i]!='\0';i++)x[i]=p->data[i];x[i]='\0';S=p->next;free(p);return true;}int main(){char a[size]; //静态数组a存放要处理的前缀表达式char right[size],left[size],tmp[size]; //right,left为弹出栈的元素,依次为右操作数和左操作数;tmp是临时变量,用于存储某些字符串char b[num_length];//静态数组b存放操作数的各位数字如231的'2'、'3'、'1'scanf("%s",&a); //需要您输入前缀表达式LiStack S;//初始化一个栈,用于存放当前暂时还不能确定运算次序的字符串形式的操作数InitStack(S); //初始化链栈int i,j=0,length=strlen(a); //length为输入的前缀表达式的总长度,i、j分别为静态数组a、b的索引下标for(i=length-1;i>=0;i--){//从右到左扫描if(a[i]>=48&&a[i]<=57){//若当前字符是数字,字符0-9的ACSII码范围是[48,57]b[j++]=a[i];if(a[i-1]==','||a[i-1]=='+'||a[i-1]=='-'||a[i-1]=='*'||a[i-1]=='/'){//若下一个字符是逗号或者运算符,则代表凑够一个操作数了int m;for(m=0;m<j;m++)tmp[m]=b[j-1-m]; //因为是从右到左扫描的,因此需要将数字颠倒一下tmp[m]='\0';Push(S,tmp); //将当前操作数入栈j=0; //将j归零}}else switch(a[i]){case '*': case '/': case '-': case '+':{//若当前字符是运算符Pop(S,left); //先出栈的是“左操作数”Pop(S,right); //后出栈的是“右操作数”if(strlen(left)+strlen(right)+1+2>size) // 左右操作数长度之和再加上操作符、左右括号的长度过长,容不下return false;tmp[0]='('; //先存左括号int k;for(k=0;k<strlen(left);k++)tmp[k+1]=left[k]; //存左操作数tmp[strlen(left)+1]=a[i]; //存运算符for(k=0;k<strlen(right);k++)tmp[k+strlen(left)+2]=right[k]; //存右操作数tmp[strlen(left)+strlen(right)+2]=')'; //最后存右括号tmp[strlen(left)+strlen(right)+3]='\0';Push(S,tmp); //将结果入栈}}}Pop(S,tmp); //若被扫描的前缀表达式是合法的,则最后栈中只会留下一个元素,就是最终结果printf("结果是:%s\n",tmp); //输出结果return 0;}

运行程序后需要输入待转换的前缀表达式,注意本程序只能处理有关运算符+、-、*、/的前缀表达式,不能是÷或者×及其他运算,本程序不会检查输入的前缀表达式是否正确,因此请您核验好自己的式子是否正确,操作数长度在10位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

END

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。