快要开始工作了,人生的第一份工作要格外重视,毕竟要有一个好的开始嘛。所以抽几天时间复习一下数据结构。看到堆栈部分,有一个运用堆栈的列子,表达式的中缀和前缀后缀的转换,刚开始找工作面试和笔试都遇到了这样的问题,以前模模糊糊的,现在搞明白了
一.表达式的三种形式:
中缀表达式:运算符放在两个运算对象中间,这是我们书写的时候最熟悉的一种形式,如:(2+1)*3
后缀表达式:不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:2 1 + 3 *
前缀表达式:同后缀表达式一样,不包含括号,运算符放在两个运算对象的前面,如:* + 2 1 3
二.中缀表达式向后缀和前缀表达式的转换
转化的过程需要一个辅助的运算符堆栈op。并且要预先给运算符设置好运算的优先级如下所示:
struct { char ch; int pri; } lpri[]={{'=',0},{'(',1},{'*',5},{'/',5},{'+',3},{'-',3},{')',6}}, rpri[]={{'=',0},{'(',6},{'*',4},{'/',4},{'+',2},{'-',2},{')',1}};
我们可以看到同一个运算符作为左(对应lpri数组)、右(对应rlpri数组)运算符时他们的优先级不同,这是为了实现表达式求值时"从左到右计算"的规定设计的。为了方便算法的实现,在op堆栈的栈地存放的是'='作为终结。
将算术表达式exp转换成后缀表达式postexp的过程如下:
初始化运算符堆栈op; 将'='进栈; 从exp读取字符ch; while(ch!='\0') { if(ch不是运算符) 将后续的所有数字均依次存放到postexp中,并以字符'#'标志数值串的结束; else switch(precede(op的栈顶运算符,ch)) { case '<': //栈顶运算符优先级低 将ch进栈; 从exp读取下一个字符ch; break; case '=': 退栈; 从exp读取下一个字符ch; break; case '>': 退栈运算符并将其存放到postexp中; break; } } 若字符串exp扫描完毕,则将运算符栈op中'='之前的所有运算符依次出栈并存放到 postexp中。最后得到后缀表达式postexp。
具体的C语言代码如下:
#include "stdafx.h" #include <iostream> #define MaxOp 10 #define MaxSize 50 struct { char ch; int pri; } lpri[]={{'=',0},{'(',1},{'*',5},{'/',5},{'+',3},{'-',3},{')',6}}, rpri[]={{'=',0},{'(',6},{'*',4},{'/',4},{'+',2},{'-',2},{')',1}}; int leftpri(char op) { int i; for(i=0;i<MaxOp;i++) if(lpri[i].ch==op) return lpri[i].pri; } int rightpri(char op) { int i; for(i=0;i<MaxOp;i++) if(rpri[i].ch==op) return rpri[i].pri; } int isOp(char ch) { if(ch=='('||ch==')'||ch=='*'||ch=='/'||ch=='+'||ch=='-') return 1; else return 0; } int precede(char op1,char op2) { if(leftpri(op1)==rightpri(op2)) return 0; else if(leftpri(op1)<rightpri(op2)) return -1; else return 1; } int precedeT(char op1,char op2) { if(leftpri(op1)==rightpri(op2)) return 0; else if(leftpri(op1)<rightpri(op2)) return 1; else return -1; } void trans(char *exp,char postexp[]) { typedef struct { char data[MaxSize]; int top; }OP; OP *op=(OP *)malloc(sizeof(OP)); int i=0; op->top=-1; op->top++; op->data[op->top]='='; while(*exp!='\0') { if(!isOp(*exp)) { while(*exp>='0'&&*exp<='9') { postexp[i++]=*exp; exp++; } postexp[i++]='#'; }else switch(precede(op->data[op->top],*exp)) { case -1: op->data[++op->top]=*exp; exp++; break; case 0: op->top--; exp++; break; case 1: postexp[i++]=op->data[op->top--]; break; } } while(op->data[op->top]!='=') { postexp[i++]=op->data[op->top--]; } postexp[i]='\0'; } void transT(char *exp,char postexp[]) { typedef struct { char data[MaxSize]; int top; }OP; OP *op=(OP *)malloc(sizeof(OP)); int i=0; op->top=-1; op->top++; op->data[op->top]='='; int j=-1; char *p=exp; while(*p!='\0') { p++; j++; } while(j>-1) { if(!isOp(exp[j])) { while(exp[j]>='0'&&exp[j]<='9') { postexp[i++]=exp[j]; j--; } postexp[i++]='#'; }else switch(precedeT(exp[j],op->data[op->top])) { case -1: op->data[++op->top]=exp[j]; j--; break; case 0: op->top--; j--; break; case 1: postexp[i++]=op->data[op->top--]; break; } } while(op->data[op->top]!='=') { postexp[i++]=op->data[op->top--]; } postexp[i]='\0'; } float compvalue(char *postexp) { typedef struct { float data[MaxSize]; int top; }OP; float a,b,c,d; OP *st = (OP *)malloc(sizeof(OP)); st->top=-1; while(*postexp!='\0') { switch(*postexp) { case '+': a=st->data[st->top--]; b=st->data[st->top--]; c=a+b; st->data[++st->top]=c; break; case '-': a=st->data[st->top--]; b=st->data[st->top--]; c=b-a; st->data[++st->top]=c; break; case '*': a=st->data[st->top--]; b=st->data[st->top--]; c=b*a; st->data[++st->top]=c; break; case '/': a=st->data[st->top--]; b=st->data[st->top--]; if(a!=0) { c=b/a; st->data[++st->top]=c; } else { printf("\0除零错误!\n"); exit(0); } break; default: d=0; while(*postexp>='0'&&*postexp<='9') { d=10*d + *postexp - '0'; postexp++; } st->data[++st->top]=d; break; } postexp++; } return st->data[st->top]; } float compvalueT(char *postexp) { typedef struct { float data[MaxSize]; int top; }OP; float a,b,c,d; OP *st = (OP *)malloc(sizeof(OP)); st->top=-1; while(*postexp!='\0') { switch(*postexp) { case '+': a=st->data[st->top--]; b=st->data[st->top--]; c=a+b; st->data[++st->top]=c; break; case '-': a=st->data[st->top--]; b=st->data[st->top--]; c=a-b; st->data[++st->top]=c; break; case '*': a=st->data[st->top--]; b=st->data[st->top--]; c=a*b; st->data[++st->top]=c; break; case '/': a=st->data[st->top--]; b=st->data[st->top--]; if(b!=0) { c=a/b; st->data[++st->top]=c; } else { printf("\0除零错误!\n"); exit(0); } break; default: d=0; while(*postexp>='0'&&*postexp<='9') { d=10*d + *postexp - '0'; postexp++; } st->data[++st->top]=d; break; } postexp++; } return st->data[st->top]; } int _tmain(int argc, _TCHAR* argv[]) { char exp[]="1+((2+3)*4)-5"; //char expT[]="1+((2+3)*4)-5"; //fanzhuan(exp,expT); //printf("expT:%s\n",expT); char postexp[MaxSize]; char postexpT[MaxSize]; trans(exp,postexp); printf("中缀表达式:%s\n",exp); printf("后缀表达式:%s\n",postexp); transT(exp,postexpT); printf("前缀表达式:%s\n",postexpT); printf("后缀表达式的值:%f\n",compvalue(postexp)); printf("前缀表达式的值:%f\n",compvalueT(postexpT)); return 0; }
哈哈,上面的代码已经包括中缀转前后缀和前后缀的求值算法实现了。
前缀和后缀表达式转换方法的区别主要在,后缀是从左往右扫描exp,前缀反之。所以两者的左右运算符的划分是相反的。这一点还体现在求值的时候。
好吧,弄好一篇了 2012-07-12