快要開始工作了,人生的第一份工作要格外重視,畢竟要有一個好的開始嘛。所以抽幾天時間復習一下數據結構。看到堆棧部分,有一個運用堆棧的列子,表達式的中綴和前綴后綴的轉換,剛開始找工作面試和筆試都遇到了這樣的問題,以前模模糊糊的,現在搞明白了
一.表達式的三種形式:
中綴表達式:運算符放在兩個運算對象中間,這是我們書寫的時候最熟悉的一種形式,如:(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
