Thuật toán chuyển đổi này được phát minh bởi vị giáo sư người Đức nổi tiếng Edsger Dijkstra (cũng là tác giả của thuật toán tìm đường đi ngắn nhất được đặt theo tên ông và semaphore, một kỹ thuật để đồng bộ các tiến trình trong lập trình đa nhiệm). Thuật toán này cũng dựa theo cơ chế ngăn xếp. Ý tưởng chung của thuật toán cũng là duyệt biểu thức từ trái sang phải:
- Nếu gặp một toán hạng (con số hoặc biến) thì ghi nó vào chuỗi kết quả (chuỗi kết quả là biểu thức trung tố).
- Nếu gặp dấu mở ngoặc, đưa nó vào stack.
- Nếu gặp một toán tử (gọi là o1 ), thực hiện hai bước sau:
o Chừng nào còn có một toán tử o2 ở đỉnh ngăn xếp VÀ độ ưu tiên của o1 nhỏ hơn hay bằng độ ưu tiên của o2 thì lấy o2 ra khỏi ngăn xếp và ghi vào kết quả.
o Push o1 vào ngăn xếp
- Nếu gặp dấu đóng ngoặc thì cứ lấy các toán tử trong ngăn xếp ra và ghi vào kết quả cho đến khi lấy được dấu mở ngoặc ra khỏi ngăn xếp.
- Khi đã duyệt hết biểu thức trung tố, lần lượt lấy tất cả toán hạng (nếu có) từ ngăn xếp ra và ghi vào chuỗi kết quả.
Biểu thức hậu tố là theo cách biểu diễn này, các toán tử sẽ được đặt sau các toán hạng. Cụ thể là biểu thức trung tố: 4+5 sẽ được biểu diễn lại thành 4 5 +.
Quá trình tính toán giá trị của biểu thức hậu tố khá tự nhiên đối với máy tính. Ý tưởng là đọc biểu thức từ trái sang phải, nếu gặp một toán hạng (con số hoặc biến) thì push toán hạng này vào ngăn xếp; nếu gặp toán tử, lấy hai toán hạng ra khỏi ngăn xếp (stack), tính kết quả, đẩy kết quả trở lại ngăn xếp. Khi quá trình kết thúc thì con số cuối cùng còn lại trong ngăn xếp chính là giá trị của biểu thức đó.
Ví dụ: biểu thức trung tố : 5 + ((1 + 2) * 4) + 3
được biểu diễn lại dưới dạng hậu tố là: 1 2 + 4 * + 3 +
Cài đặt thuật toán.
#include<stdio.h> #include<conio.h> #include<math.h> #include<ctype.h> #include<string.h> #include<stdlib.h> float number[200]={0}; int n=0;
/* chuyen sang dang hau to*/ char st[100];
/*Ham cho queue Char*/
char queueChar[200]={'@'};int first=0,last=0; int isEmptyQueueChar(){return last==0;};
void emptyQueueChar(){last=first=0;} void baoloi(char *x){
clrscr();
printf(" Khong the tinh %s\n",st); puts(x);
getch(); abort(); }
// Ham dung cho queue, queue la ket qua cua qua trinh phan tich sang hau to void pushQueueChar(char x){ last++; queueChar[last]=x; } char getQueueChar(){ last++; return queueChar[last-1]; } /*====================================*/
// Stack dung de lam bo nho tam, phuc vu cho qua trinh phan tich sang hau to char stack[200],top=0;
void empty(){ // Khoi tao stack top=0;
}
int isemptyStack(){ //Kiem tra stack co rong return top==0;
}
void pushStack(char x){ //Dua mot ky tu vao stack top+=1;
stack[top]=x; }
char popStack(){ // Lay ky tu ra top-=1;
return stack[top+1]; }
char getStack(){ // xem ky tu dinh return stack[top];
}
int priority(char x){// Tinh muc uu tien
if(strchr("!~SCTPELaA",toupper(x)))return 4;//Cac phep toan 1 hang tu uu tien cao nhat if(strchr("*/^%&|\\",toupper(x)))return 3;
if(x=='+' || x=='-')return 2; if(x=='(' || x==')')return 1;
if(x>='0' && x<='9')return 0;//Cac so co muc uu tien thap nhat return -1;
}
//Ham lay 1 so tu chuoi
// vi du 12+36, so o vi tri tu 3~4 la 36 float getNumber(int b,int e){
int i;
char x[20]={0};
for(i=b;i<=e;i++)x[i-b]=st[i];
return atof(x);//ham co san, chuyen chuoi sang so }
//Ham nay chuyen st la phep tinh dang trung to (kieu viet tu nhien) //Sang dang hau to : la dang de tinh toan
// Vi du 1+2 chuyen thanh 1 2 + void Convert(){ empty(); emptyQueueChar();last=0; int i=0,j=0; char x; do{ switch(priority(st[i])){ case 0://So hang, cac chu so
j=i+1;
while((isdigit(st[j]) || st[j]=='.'))j++; //Tim ky tu ko phai la so
number[n]=(getNumber(i,j-1)); //lay gia tri so o day pushQueueChar(-n);//Dua vao queueChar
n++; i=j-1; break;
case 1: // La dau mo/dong ngoac ( hoac ) if(st[i]=='(')pushStack('('); else do{ x=popStack(); if(x!='(') pushQueueChar(x); }while(x!='('); break;
case 2://phep toan 2 hang tu +,- Co muc uu tien thap case 3://Phep toan 1 hang tu */^...Muc uu tien cao
while(!isemptyStack() && (priority(st[i])<=priority(getStack()))) //UU tien dua */&^ truoc +- vi */ co uu tien cao hon +-
pushQueueChar(popStack()); pushStack(st[i]);
break;
case 4://cac toan tu 1 hang tu, nhu sin, cos, tan, cac hang so switch(st[i]){
case 'c':
case 'C'://Xem co phai la COS khong
if((toupper(st[i+1])=='O')&&(toupper(st[i+2])=='S')){ pushStack('c');
i+=2;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break;
case 's':
case 'S'://Xem co phai la Sin ko
if((toupper(st[i+1])=='I')&&(toupper(st[i+2])=='N')){ pushStack('s');
i+=2;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break;
case 't':
case 'T': //Co phai la tan
if((toupper(st[i+1])=='A')&&(toupper(st[i+2])=='N')){ pushStack('t');
i+=2;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break;
case 'l':
case 'L'://Co the la Log, ln
if((toupper(st[i+1])=='O')&&(toupper(st[i+2])=='G')){ pushStack('l'); i+=2; }else if((toupper(st[i+1])=='N')){ pushStack('L'); i+=1;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break;
case 'e':
case 'E'://neu ko phai la EXP thi la e=2.71828
if((toupper(st[i+1])=='X')&&(toupper(st[i+2])=='P')){ pushStack('e'); i+=2; }else { i++; number[n]=M_E;
pushQueueChar(-n); n++;
}break; case 'p':
case 'P'://Co phai la PI if((toupper(st[i+1])=='I')){ i++; number[n]=M_PI; pushQueueChar(-n); n++; }break; case 'a': case 'A': switch(st[i+1]){ case 'c':
case 'C'://Xem co phai la COS khong
if((toupper(st[i+2])=='O')&&(toupper(st[i+3])=='S')){ pushStack('C');
i+=3;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break;
case 's':
case 'S'://Xem co phai la Sin ko
if((toupper(st[i+2])=='I')&&(toupper(st[i+3])=='N')){ pushStack('S');
i+=3;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break;
case 't':
case 'T': //Co phai la tan
if((toupper(st[i+2])=='A')&&(toupper(st[i+3])=='N')){ pushStack('T');
i+=3;
}else baoloi("Syntax error : ham khong duoc khai bao !"); break; } break; case '!':pushQueueChar('!');break; case '~':pushQueueChar('~');break; }break; } i++; }while(i<strlen(st)); while(!isemptyStack())pushQueueChar(popStack()); } /*===========================================================*/ //Ham phuc vu bao loi, tranh cac loi nhu log(0)
int matherr (struct exception *a) {
if (a->type == DOMAIN) baoloi("Loi tham so");
else baoloi(strcat("Math error : Loi khi tinh ham ",a->name)); return 0;
}
float giaithua(float x){ float t=1,i=1;
if(x!=(int)x)baoloi("Math error : Loi khi tinh giai thua cua so thuc"); else if(x>33)baoloi("Math error : So qua lon khi tinh giai thua"); for(;i<=x;i++)t*=i;
return t; }
//cac phep toan 1 toan tu nhu sin, cos, tan, giai thua float tinh1(float x,char pt){
switch(pt){
case 's':return sin(x); case 'S':return asin(x); case 'c':return cos(x); case 'C':return acos(x); case 't':return tan(x); case 'T':return atan(x); case '~':return ~((int)x); case '!':return giaithua(x); case 'l':return log10(x); case 'L':return log(x); case 'e':return exp(x); };
return 0; }
//Phep toan 2 hang tu nhu +, -, *, /, ^ .... float tinh2(float x,float y, char pt){ switch(pt){
case '+':return x+y; case '-':return x-y; case '*':return x*y;
case '%':return ((int)x)%((int)y); case '\\':return (int)x /(int) y; case '&':return (int)x&&(int) y; case '|':return (int)x ||(int) y; case '/':
if(y==0)baoloi("Loi chia cho 0"); return x/y;
case '^':return pow(x,y); }
return 0; }
float StackTinh[200]={0};int topStackTinh=0;
void pushStackTinh(float x){topStackTinh++;StackTinh[topStackTinh]=x;} float getStackTinh(){topStackTinh--;return StackTinh[topStackTinh+1];} float tinhtoan(){ int i; float a,b,c; for(i=1;i<=last;i++) if(queueChar[i]>0){ if(priority(queueChar[i])<=3){
//neu la phep toan 2 hang tu nhu +,-,*,/,^ , priority=3 //lay ra 2 so gan nhat roi tinh toan, thay gia tri vao if(topStackTinh<2)baoloi(0); b=getStackTinh(); a=getStackTinh(); c=tinh2(a,b,queueChar[i]); pushStackTinh(c); }else{
//Neu la phep toan 1 hang tu, priority=4 //Lay ra 1 so va tinh toan, the vao if(topStackTinh<1)baoloi(0); a=getStackTinh(); c=tinh1(a,queueChar[i]); pushStackTinh(c); } }else{
//Neu la 1 so thi dua vao stack c=number[-queueChar[i]]; pushStackTinh(c); } return c; } void xuat_hau_to(){
int i; for(i=1;i<=last;i++) if(queueChar[i]>0)printf("%c",queueChar[i]); else printf("{%g}",number[-queueChar[i]]); } void main(){ clrscr();
printf("\t Tinh gia tri bieu thuc\n Nhap bieu thuc nhu binh thuong\n"); printf(" Cac phep toan +-*/%!|^\\\n");
printf(" Cac ham sin,asin,cos,acos,tan,atan,log,ln,exp\n"); printf(" Cac hang pi=3.1415926535, e=2.718281828\n"); printf("\n\n\n\n St = ");gets(st); //Doc phep toan
Convert(); //Chuyen sang hau to : 12+34*56 --> 12 34 56 * + printf("\n Dang hau to : ");
xuat_hau_to();printf("\n");
printf("\n\n\n\n %s = %g",st,tinhtoan()); getch();
//return 0; }