文章目录

  • 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 三种算术表达式

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

类型 规则 例1 例2
中缀表达式 运算符在两个操作数中间 a+b a+b-c
后缀表达式 运算符在两个操作数后面 ab+ ab+c-
前缀表达式 运算符在两个操作数前面 +ab -+abc

2 后缀表达式相关考点

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

2.1.1 手算

中缀转后缀的手算步骤:

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

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

转换前的中缀表达式 转换后的后缀表达式
((15/(7-(1+1)))*3)-(2+(1+1)) 15 7 1 1 + - / 3 * 2 1 1 + + -
2+(3+4)*5 2 3 4 + 5 * +
16+2*30/4 16 2 30 * 4 / +

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;
}

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

输入 输出
((15/(7-(1+1)))*3)-(2+(1+1)) 15 7 1 1 + - / 3 * 2 1 1 + + -
2+(3+4)*5 2 3 4 + 5 * +
16+2*30/4 16 2 30 * 4 / +

2.2 后缀表达式求值

2.2.1 手算

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

求值前 求值后
15 7 1 1 + - / 3 * 2 1 1 + + - 5
2 3 4 + 5 * + 37
16 2 30 * 4 / + 31

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位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

输入 输出
15,7,1,1,+,-,/,3,*,2,1,1,+,+,- 5.00
2,3,4,+,5,*,+ 37.00
16,2,30,*,4,/,+ 31.00

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

2.3.1 手算

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

转换前的后缀表达式 转换后的中缀表达式
15 7 1 1 + - / 3 * 2 1 1 + + - (((15/(7-(1+1)))*3)-(2+(1+1)))
2 3 4 + 5 * + (2+((3+4)*5))
16 2 30 * 4 / + (16+((2*30)/4))

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位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

输入 输出
15,7,1,1,+,-,/,3,*,2,1,1,+,+,- (((15/(7-(1+1)))*3)-(2+(1+1)))
2,3,4,+,5,*,+ (2+((3+4)*5))
16,2,30,*,4,/,+ (16+((2*30)/4))

3 前缀表达式相关考点

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

3.1.1 手算

中缀转前缀的手算步骤:

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

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

转换前的中缀表达式 转换后的前缀表达式
((15/(7-(1+1)))*3)-(2+(1+1)) - * / 15 - 7 + 1 1 3 + 2 + 1 1
2+(3+4)*5 + 2 * + 3 4 5
16+2*30/4 + 16 * 2 / 30 4

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;
}

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

输入 输出
(((15/(7-(1+1)))*3)-(2+(1+1))) - * /15 -7 +1 1 3 +2 +1 1
(2+((3+4)*5)) +2 * +3 4 5
(16+(2*(30/4))) +16 *2 /30 4

3.2 前缀表达式求值

3.2.1 手算

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

求值前 求值后
- * / 15 - 7 + 1 1 3 + 2 + 1 1 5
+ 2 * + 3 4 5 37
+ 16 * 2 / 30 4 31

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位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

输入 输出
+,16,*,2,/,30,4 31.00
+,2,*,+,3,4,5 37.00
-,*,/,15,-,7,+,1,1,3,+,2,+,1,1 5.00

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

3.3.1 手算

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

转换前的前缀表达式 转换后的中缀表达式
- * / 15 - 7 + 1 1 3 + 2 + 1 1 (((15/(7-(1+1)))*3)-(2+(1+1)))
+ 16 * 2 / 30 4 (16+(2*(30/4)))
+ 2 * + 3 4 5 (2+((3+4)*5))

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位以内且必须是整数,请将不同的操作数之间、运算符之间、运算符与操作数之间用英文状态的逗号即","隔开。下面是三个输入输出示例:

输入 输出
+,16,*,2,/,30,4 (16+(2*(30/4)))
+,2,*,+,3,4,5 (2+((3+4)*5))
-,*,/,15,-,7,+,1,1,3,+,2,+,1,1 (((15/(7-(1+1)))*3)-(2+(1+1)))

END

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

  1. pnd1 c语言,c语言实现中缀后缀前缀表达式相互转化并求值

    <c语言实现中缀后缀前缀表达式相互转化并求值>由会员分享,可在线阅读,更多相关<c语言实现中缀后缀前缀表达式相互转化并求值(21页珍藏版)>请在人人文库网上搜索. 1.1)表达 ...

  2. 使用栈解决的一类经典问题:表达式转换及求值;中缀表达式;前缀表达式,后缀表达式,中缀转前缀;中缀转后缀;后缀表达式求值;波兰式,逆波兰式

    文章目录 背景知识 表达式转换问题(考研经典) 一:手工转换 (1)中缀转前缀和中缀转后缀 (2)前缀转中缀和后缀转中缀 二:用栈实现表达式转换 (1)中缀转后缀 (2)中缀转前缀 表达式计算问题(使 ...

  3. 前缀表达式的计算机求值

    前缀表达式的计算机求值特点 引例:某表达式的前缀形式为"+ -*^ABCD/E/F+GH",那么它的中缀形式为? 前缀表达式的操作 前缀表达式是一种没有括号的算术表达式,就是前序表 ...

  4. python【数据结构与算法】表达式(前缀中缀后缀表达式)与Two fork tree

    文章目录 1 相关概念 2 与二叉树关系 3 表达式转换 4 另一种方法 1 相关概念 前缀表达式(Prefix Notation)是指将运算符写在前面操作数写在后面的不包含括号的表达式,而且为了纪念 ...

  5. 数据结构:前缀,中缀,后缀表达式(逆波兰表达式)

    前缀表达式(波兰表达式) 前缀表达式的运算符位于操作数之前. 比如 (1+2)*3-4  对应的前缀表达式就是: - * + 1 2 3 4 前缀表达式的计算机求值 从右至左扫描表达式,遇到数字时,就 ...

  6. 前缀 中缀 后缀表达式

    1.前缀表达式叫波兰式,后缀叫逆波兰式 2.中缀表达式转另外两个比较简单,前后缀装中缀较麻烦 3.问题分求表达式还是求值,如果是求值则需要两个栈,一个是操作符栈,一个是操作数栈,等操作符栈入栈完毕后依 ...

  7. 前缀中缀后缀表达式的计算求值

    原文在这里 表达式 前缀表达式(波兰表达式) 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前 举例说明: (3+4)×5-6 对应的前缀表达式就是 - × + 3 4 5 6 前缀表达式求值 ...

  8. 中缀表达式到前缀表达式和后缀表达式

    1.算法思路 转化为后缀:从左到右遍历中缀表达式,遇到操作数,输出,遇到操作符,当前操作符的优先级大于栈顶操作符优先级,进栈,否则,弹出栈顶优先级大于等于当前操作符的操作符,当前操作符进栈.     ...

  9. 前缀(波兰表达式) 中缀 后缀(逆波兰表达式)

    前缀.中缀.后缀表达式(逆波兰表达式) 本文转自https://www.cnblogs.com/chensongxian/p/7059802.html 介绍 前缀表达式.中缀表达式.后缀表达式都是四则 ...

  10. 中缀表达式转换成前缀表达式和后缀表达式的极其简单方法

    35,15,+,80,70,-,*,20,/ //后缀表达方式 (((35+15)*(80-70))/20)=25 //中缀表达方式 /,*,+,35,15,-,80,70, 20 //前缀表达方式 ...

最新文章

  1. Centos7 使用Docker安装tomcat
  2. 使用pytorch创建神经网络并解决线性拟合和分类问题
  3. Mozilla网站安全分析工具Observatory已发布
  4. Oracle数据库升级与补丁
  5. c++基础学习(10)--(文件、流、异常处理、动态内存、命名空间)
  6. 设置ubuntu默认python3设置
  7. binlog和redo log的区别
  8. asp.net core webapi Session 内存缓存
  9. 网络ip计算器工具_火影忍者联名款计算器上市,卡西欧玩转IP联合
  10. word自带公式右侧编号
  11. Shell脚本学习-阶段九-数据库被攻击恢复
  12. php字符串中删除字符串函数,PHP实现删除字符串中任何字符的函数
  13. 我的2006总结:一个结束和一个开始
  14. EndNote文献输出引用格式自定义修改与编辑界面解读
  15. java九宫格代码_Java实现九宫格的简单实例
  16. 邮件开头结尾一些不同的表达
  17. [CSP冲刺班]CSP-J2021模拟赛#9
  18. Java实现简单的弹窗
  19. 十 三 弟 你 快 回 来 吧, 皇 帝 四 哥 叫 你 一 起 学 习 大 数 据 呢
  20. 深大uooc大学生心理健康章节答案第十一章

热门文章

  1. 解决网页内容无法复制的方法
  2. 腾讯视频qlv格式怎么转换成mp4在手机上播放
  3. 各种文件的mime类型
  4. vue中局部过滤器和全局过滤器的使用
  5. 企业微信 网页授权登入demo
  6. jmeter性能测试2-模拟多用户登录
  7. 接口测试 requests的身份认证方式
  8. linux进程sl是什么,Linux ps state sl+是什么意思
  9. kettle 提交数据量_kettle大数据量读写mysql性能优化
  10. 浏览器中点击链接,跳转qq添加好友的实现方式