中綴表達式:算法
把運算符放在參與運算的兩個操做數中間的表達式稱做中綴表達式例:「3+4*5-6/2」,由於中綴表達式計算時必須按照優先級從左向右計算,因此計算機在進行中綴表達式求值時比較麻煩,然後綴表達式求值比較方便。express
後綴表達式:數組
把運算符放在參與運算的兩個操做數後面的表達式稱做後綴表達式。ide
例:中綴表達式:3+4*5-6/2函數
轉換成後綴表達式: 3 4 5 * + 6 2 / -spa
中綴表達式:9-8*(4-3)指針
轉換成後綴表達式: 9 8 4 3 - * -blog
轉換規則:索引
按照優先級,把每一個運算符都移到它的兩個操做數的後面,再刪除全部的括號內存
後綴表達式的求值:
從左向右一次掃描後綴表達式,遇到運算符將將它前面的兩個運算數取出並計算,並將結果帶入後綴表達式,直到掃描到最後一個後綴表達式。
表達式求值:
表達式求值是棧應用的一個基本例子,輸入一箇中綴表達式,求取相應的結果。由於計算機不會算中綴表達式,因此咱們先要將中綴表達式轉換成相應的後綴表達式再進行計算。要轉成相應的後綴表達式,咱們應該建立兩個棧,一個用來存放操做數,一個用來存放運算符。
中綴表達式求值的算法:
從左向右掃描中綴表達式,若遇到操做數,則直接壓入運算數棧,若遇到符號,則與運算符棧的棧頂元素比較,若讀取符號的優先級高,則讀取的符號進棧;不然讓運算符棧的棧頂符號退棧而且將運算數棧最上面的兩個元素退棧,而後將運算的結果壓入運算數棧,一直這樣循環直到讀取的符號的優先級高於運算符棧頂元素。
由於每讀取一個符號就要與運算符棧的棧頂元素進行優先級比較,咱們不能每次都寫一大堆if else語句,因此咱們能夠將運算符的優先級的結果放到一個二維數組中,而後利用查表法,判斷優先級。
由於當咱們讀取第一個符號時,運算符棧仍是個空棧,爲了方便比較,咱們在棧底壓入一個#,並規定#的優先級最低,並將「#」做爲表達式輸入結束的標誌。
爲了方便索引:咱們再建立一個一維數組,
char arr[7] = { '+' , '-', '*', '/', '(', ')', '#' };經過它來找到棧頂符號和讀取符號在優先級數組中的位置。
實現:輸入一個合法的中綴表達式,只包含「+ - * /」四種運算符,並以「#」做爲結束標誌。 //函數聲明: #include<stdio.h> #include<stdlib.h> #define STACK_INIT_MEMORY 20 //初始時開闢棧的內存大小 #define STACK_GROW_MEMORY 10 //當棧滿時,追加內存的大小 const char arr[7]; //聲明一個存放運算符的一維數組,做爲索引 void init_priority_list(char list[][7]); //初始化符號表 typedef struct stack_num //聲明一個存放運算數的結構體類型 { int *esp; //棧頂指針 int *ebp; //棧底指針 int size; //記錄當前棧空間最多能存幾個元素 }stack_num; void creatstack_num(stack_num *S); //建立存放運算數的棧 void push_num(stack_num *S, int x); //將參數x中的數壓入運算數棧中 int pop_num(stack_num *S, int *x); //彈出棧頂元素,並經過形參x帶回 typedef struct stackpop_opreation //聲明一個存放運算符的結構體類型 { char *esp; //棧頂指針 char *ebp; //棧底指針 int size; //記錄當前棧空間最多能存幾個元素 }stack_operation; void creatstack_operation(stack_operation *S); //建立一個存放運算符的棧 void push_operation(stack_operation *S, char symbol); //將符號壓入運算符棧中 int pop_opreation(stack_operation *S, char *top); //將運算符棧中的棧頂元素彈出 //函數實現: char judge_priority(stack_operation* S, char c); //判斷讀取的運算符與棧頂符號的優先級,並返回 int operation(int a, char symbol, int b); //對運算數進行相的運算,並將結果返回 int judge_num(char c); //判斷讀取的是符號仍是數字,若是是數字返回1 #include"expression.h" const char arr[7] = { '+', '-', '*', '/', '(', ')', '#' }; //經過arr[7]來查找list[][]中的優先級 void init_priority_list(char list[][7]) //初始化優先級列表 { int arr2[7] = { 1, 1, 2, 2, 3, 0, -1 }; //列做爲棧頂元素,行表明讀取的運算符 for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if ((i == 4 && j == 5) || (i == 6 && j == 6) //令'('與‘)’,‘#’與‘#’優先級相同 list[i][j] = '='; else { if (arr2[i] >= arr2[j]) list[i][j] = '>'; //棧頂優先級高 else if (arr2[i] <= arr2[j]) list[i][j] = '<'; //讀取的運算符優先級高 } } } } void creatstack_num(stack_num *S) //建立運算數棧 { S->ebp = (int *)malloc(sizeof(int)* STACK_INIT_MEMORY); if (S->ebp == NULL) //判斷動態內存是否開闢成功 exit(1); S->size = STACK_INIT_MEMORY; S->esp = S->ebp; //讓棧頂指針指向棧底 } void push_num(stack_num *S, int x) { if (S->esp - S->ebp >= S->size) //判斷當前棧是否已滿 { //棧滿追加空間 S->ebp = (int *)realloc(S->ebp, sizeof(int)*(S->size + STACK_GROW_MEMORY)); if (S->ebp == NULL) exit(1); S->esp = S->ebp + S->size; //讓棧頂指針向後偏移指向要入棧的位置 S->size += STACK_GROW_MEMORY; //更新棧的size } *S->esp++ = x; } int pop_num(stack_num *S, int *x) { if (S->esp == S->ebp) return 0; //若是是空棧,則返回0 else { *x = *--S->esp; return 1; //若是彈出成功,返回1,並將彈出的元素保存在x中帶回 } } void creatstack_operation(stack_operation *S) //建立運算符棧 { S->ebp = (char *)malloc(sizeof(char)*STACK_INIT_MEMORY); if (S->ebp == NULL) exit(1); //判斷動態內存是否開闢成功 S->size = STACK_INIT_MEMORY; S->esp = S->ebp; } void push_operation(stack_operation *S, char symbol) { if (S->esp - S->ebp >= S->size) //若是棧滿則追加空間 { S->ebp = (char *)realloc(S->ebp, sizeof(char)*(S->size += STACK_GROW_MEMORY)); if (S->ebp == NULL) exit(1); S->ebp = S->ebp + S->size - STACK_GROW_MEMORY; } *S->esp++ = symbol; } int pop_opreation(stack_operation *S, char *top) { if (S->esp == S->ebp) return 0; //若是棧是空棧,則返回0 else *top = *--S->esp; //不然將彈出的勻速保存在top中帶回 return 1; } char judge_priority(stack_operation* S, char c) //判斷棧頂運算符與讀取的運算符的優先級 { char list[7][7]; init_priority_list(list); //初始化優先級表 int line = 0; int row = 0; for (line = 0; line < 7; line++) { if (arr[line] == *(S->esp - 1)) //將棧頂符號在arr[]中的位置做爲行下標 break; } for (row = 0; row < 7; row++) { if (arr[row] == c) //將讀取的運算符在arr[]中的位置做爲列下標 break; } return list[line][row]; //經過優先級表,返回優先級關係 } int operation(int a, char symbol, int b) { int ret = 0; switch (symbol) { case '+': ret = a + b; break; case '-': ret = a - b; break; case '*': ret = a*b; break; case '/': ret = a / b; break; default: break; } return ret; } int judge_num(char c) //判斷讀取的是否是數字 { int i = 0; for (i = 0; i < 7; i++) { if (arr[i] == c) break; } if (i == 7) return 1; //若是是數字則返回1 else return 0; //若是不是數字則返回0 } #include"expression.h" int main() { stack_num num_stack; creatstack_num(&num_stack); //創建一個運算數棧 stack_operation operator_stack; creatstack_operation(&operator_stack); //創建一個運算符棧 int c; char symbol; int a = 0; int b = 0; int ret = 0; push_operation(&operator_stack, '#'); //將‘#’入棧,做爲運算符棧的棧底 c=getchar(); while (c!='#'||*(operator_stack.esp-1)!='#') //接受表達式而且判斷表達式是否輸入完畢 { if (judge_num(c)) //若是是數字則進入運算數棧 { int num = 0; while (judge_num(c)) //把連續的char類型的數字所有讀取並轉化成相應的整數 { num = num * 10 + (c-'0'); //由於這是的運算數是char類型,因此先要轉換成int c = getchar(); } push_num(&num_stack,num); //將運算數入棧 } else { switch (judge_priority(&operator_stack,c)) //判斷讀取的運算符與棧頂符號的優先級關係 { case '<': //若是讀取的符號優先級高,則直接進入運算符棧 push_operation(&operator_stack, c); c=getchar(); break; case '>': //若是讀取的符號優先級低,則棧頂符號退棧,將運算結果入棧 pop_opreation(&operator_stack, &symbol); //則棧頂符號退棧 pop_num(&num_stack, &b); pop_num(&num_stack, &a) // 將運算數棧棧頂的兩個元素彈出 ret=operation(a, symbol, b); //將這兩個元素進行運算 push_num(&num_stack, ret); //將運算結果入棧 break; case '=': //當讀取到「)」時則一直退棧直到遇到「(」 pop_opreation(&operator_stack, &symbol); c=getchar(); break; default: break; } } } printf("%d\n", *(num_stack.esp-1)); //將運算數棧最後剩下的數輸出 system("pause"); free(num_stack.ebp); free(operator_stack.ebp); return 0; }