结合性:当优先级相同时,看结合性,若是从左到右结合就是先算左边的运算符,从右到左就是先算右边的运算符。
优先级:谁优先级别高谁先运算
结合性列子:如a*b/c%d/e 因为运算符都是自左向右结合的所以 运算顺序为 ((((a*b)/c)%d)/e )
优先级:a/b-c+d*e-a*c -> ((((a/b)-c)+(d*e))-(a*c))
(人习惯用)中缀表达式:二元运算符放在2个操作数的中间,书写表达式的标准方式是中缀表达式
(编译器用)后缀表达式:使用的是无括号的表达式
如
中缀表达式 后缀表达式
2+3*4 234*+
a*b+5 ab*5+
(1+2)*7 12+7*
a/b*c ab/c*
((a/(b-c+d))*(e-a)*c abc-d+/ea-*c*
a/b-c+d*e-a*c ab/c-de*+ac*-
中缀表达式到后缀表达式的转换(手工算法):
1.给每个表达式加上括号
2.将移动每个二元运算符,将其放在与其相应括号的右括号处
3.删除所有括号
如: 中缀表达式为:a/b-c+d*e-a*c
执行第一步:((((a/b)-c)+(d*e))-(a*c))
执行第二步:((((ab/)c-)(de*)+)(ac*)-)
执行第三部:ab/c-de*+ac*-
后缀表达式为:ab/c-de*+ac*-
手工算法:计算机执行效率低,因为需要2遍扫描,第一遍扫描加括号,第二遍扫描移动运算符
计算机算法:
准备一个栈,操作数立即入栈,算法判断优先级后入栈,优先级高的先入栈
即遇到操作数操作数就入栈,遇到算符先考虑优先级高的入栈。
中缀表达式转换为后缀表达式函数
1 #include<stdio.h> 2 3 #define MAX_STACK_SIZE 100 //栈长度 4 #define MAX_EXPR_SIZE 100 //最大表达式长度 5 6 7 typedef enum{ 8 lparen,rparen,plus,minus,times,divide,mod,eos,operand 9 } precedence; //运算符定义 ()+-*、% 错误 运算数 10 11 precedence stack[MAX_STACK_SIZE]; 12 static int isp[]={0,19,12,12,13,13,13,0};//()+-*/%eos的栈内优先级 13 static int icp[]={20,19,12,12,13,13,13,0};//()+-*/%eos的引入 优先级 14 int stack[MAX_STACK_SIZE]; 15 int expr[MAX_EXPR_SIZE]; //输入字符串 16 17 void postfix(void) 18 { 19 /* 20 中缀式转为后缀式 21 */ 22 char symbol; 23 precedence token; 24 int n=0; 25 int top=0; 26 stack[0]=eos; 27 for(token =get_token(symbol,&n); token!=eos; token =get_token(symbol,&n)){ 28 if(token==operand) //当时运算符直接输出 29 printf("%c"); 30 else if(token==rparen){ //有括号的情景,当遇到右括号时,一直出栈到栈顶是左括号 31 while(stack[top]!=lparen) 32 printf(delete(&top)); 33 delete(&top); 34 } 35 else{ 36 while(isp[stack[top]]>=icp[token])//比较优先级 37 printf(delete(&top)); 38 add(&top,&token); 39 } 40 } 41 while((token=delete(&top))!=eos) 42 prit_token(token); 43 printf("\n"); 44 45 }
后缀式求值函数
1 void postfix(void) 2 { 3 /* 4 中缀式转为后缀式 5 */ 6 char symbol; 7 precedence token; 8 int n=0; 9 int top=0; 10 stack[0]=eos; 11 for(token =get_token(symbol,&n); token!=eos; token =get_token(symbol,&n)){ 12 if(token==operand) //当时运算符直接输出 13 printf("%c"); 14 else if(token==rparen){ //有括号的情景,当遇到右括号时,一直出栈到栈顶是左括号 15 while(stack[top]!=lparen) 16 printf(delete(&top)); 17 delete(&top); 18 } 19 else{ 20 while(isp[stack[top]]>=icp[token])//比较优先级 21 printf(delete(&top)); 22 add(&top,&token); 23 } 24 } 25 while((token=delete(&top))!=eos) 26 prit_token(token); 27 printf("\n"); 28 29 }
获取当前字符串的字符:
1 precedence get_token(char *symbol,int *n) 2 { 3 /* 4 从输入字符串取出一个标记符号的函数 5 得到下一个字符给symbol,判断后返回字符相应的值 6 */ 7 *symbol=expr[(*n)++]; 8 switch(*symbol){ 9 case '(': return lparen; 10 case ')': return rparen; 11 case '+': return plus; 12 case '-': return minus; 13 case '/': return divide; 14 case '*': return times; 15 case '%': return mod; // 16 case ' ': return eos; //eos结束符号 17 default : return operand; //没有错误检查,默认是操作数 18 } 19 20 }
precedence stackp[MAX_STACK_SIZE];
int stack[MAX_STACK_SIZE];
这2个栈的实现参考前面的简单栈的实现