以前在大四升碩0的時後,因為太菜了,所以被老板要求寫這些資料結構程式當作練功,資料結構在研究所考試時是必考的,所以我以為我還算熟 , 但要實作程式出來又是另一回事了,可見在大學時真的背太多了 。最近整裡硬碟資料找到當初寫的code,所以在此做一下紀錄 。
主要是參考 Horowitz 資料結構聖經版
http://www.amazon.com/Fundamentals-Data-Structures-Ellis-Horowitz/dp/0929306406
這個中序轉後序程式可分為三個部份:
1. 運算元(A-Z ,0-9)與運算子( + - * / )的分離
- 使用isalnum()可以將數字/字母與符號分離
2. 堆疊的操作
- push() & pop()
3. 後序轉換演算法
- 在於比較運算子的優先權:左右括號 > 乘除 >加減
#include<stdio.h> #include<stdlib.h> #include<ctype.h> #define STACK_SIZE 50 #define ADD_SUB 1 /* 代表 加減 */ #define MULT_DIV 2 /* 代表 乘除 */ #define LEFT 3 /* 代表左括號 */ #define RIGHT 4 /* 代表右括號 */ char stack[STACK_SIZE]; /* 堆疊陣列 */ int top=-1; /* 堆疊頂端指標 */ int priority[STACK_SIZE]; /*優先權堆疊 */ void push(char s,int number){ if(top>=STACK_SIZE-1){ printf("堆疊滿了"); } else{ top++; stack[top]=s; priority[top]=number; } } void pop(){ if (top==-1){ printf("堆疊已空\n"); } else{ /*不要印出 '('*/ if( priority[top ]!=LEFT){ printf("%c",stack[top]); } top--; } }
/* 運算子處理 */ void Operator(char ch,int number) { if(top==-1&&number!=RIGHT) /* 若堆疊為空 直接push */ push(ch,number); else{ switch(number){ /* 若輸入為 ')' 從堆疊頂端依序pop直到出現'(' */ case RIGHT: for(priority[top];priority[top]!=LEFT;pop()) ; pop();//把最後的 '(' pop 但不印出 break; /* 若輸入為 '(' 直接 PUSH */ case LEFT: push(ch,number); break; /* 若輸入是 '+' '-' '*' '/' */ case ADD_SUB: case MULT_DIV: if( priority[top]==LEFT||priority[top]<number){ push(ch,number); } else{ /* 若堆疊內優先權 大於number */ while((priority[top]>=number)&&priority[top]!=LEFT) pop(); /* 先POP 堆疊內再PUSH number */ push(ch,number); } break; /*當字串已scan完 堆疊不為空 pop 剩下的運算子*/ case 0: while(top!=-1) pop(); break; } } }
int main(void){ char *IndString; char buf[STACK_SIZE]; int i=0; int error_OP = 0; printf("請輸入中序 :"); IndString=gets(buf);//中序輸入 printf("\n"); printf("後序為:"); /*若不等於結束字元*/ while(*(IndString+i)!='\0' & !error_OP) { /*數字和字母是運算元所以直接印出 */ if(isalnum(*(IndString+i))) { printf("%c",*(IndString+i)); } else if(ispunct(*(IndString+i))) { //若不是數字 空白 字母 則為真 switch(*(IndString+i)){ case '+': Operator(*(IndString+i),ADD_SUB); break; case '-': Operator(*(IndString+i),ADD_SUB); break; case '*': Operator(*(IndString+i),MULT_DIV); break; case '/': Operator(*(IndString+i),MULT_DIV); break; case '(': Operator(*(IndString+i),LEFT); break; case ')': Operator(*(IndString+i),RIGHT); break; default: printf(" error Operator\n"); error_OP = 1; break; } } i++; } Operator('\0',0);//字串scan結束 puts("\n------------------------------------\n"); return 0; }
ps: 程式裡有使用到gets,通常建議改成fgets使用,不過懶得改了
執行結果: