快要开始工作了,人生的第一份工作要格外重视,毕竟要有一个好的开始嘛。所以抽几天时间复习一下数据结构。看到堆栈部分,有一个运用堆栈的列子,表达式的中缀和前缀后缀的转换,刚开始找工作面试和笔试都遇到了这样的问题,以前模模糊糊的,现在搞明白了
一.表达式的三种形式:
中缀表达式:运算符放在两个运算对象中间,这是我们书写的时候最熟悉的一种形式,如:(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