栈应用:中缀表达式转后缀表达式
網(wǎng)上有很多關(guān)于中綴轉(zhuǎn)后綴的文章,很多文章或多或少都有bug,包括一些教學(xué)視頻,經(jīng)過本人無數(shù)次測試,保證下面的代碼運(yùn)算結(jié)果的正確性!前提是你寫的中綴表達(dá)式是正確的哈,沒有做中綴表達(dá)式是否正確的的完整性校驗(yàn)。采用的c語言編寫的哈。
中綴、后綴表達(dá)式區(qū)別
?
?
中綴表達(dá)式:(或中綴記法)是一個通用的算術(shù)或邏輯公式表示方法, 操作符是以中綴形式處于操作數(shù)的中間(例:3 + 4),中綴表達(dá)式是人們常用的算術(shù)表示方法。
?
后綴表達(dá)式:后綴表達(dá)式,指的是不包含括號,運(yùn)算符放在兩個運(yùn)算對象的后面,所有的計(jì)算按運(yùn)算符出現(xiàn)的順序,嚴(yán)格從左向右進(jìn)行(不再考慮運(yùn)算符的優(yōu)先規(guī)則)
可以通過 2個表達(dá)式計(jì)算的結(jié)果,證明是否轉(zhuǎn)換正確。
中綴、轉(zhuǎn)后綴規(guī)則
規(guī)則摘抄大話數(shù)據(jù)結(jié)構(gòu)中的描述 ,中綴表達(dá)式轉(zhuǎn)后綴表達(dá)式規(guī)則:
從左到右遍歷中綴表達(dá)式的每個數(shù)字和符號,若是數(shù)字就輸出,即成為后綴表達(dá)式的一部分;
若是符號,則判斷其與棧頂符號的優(yōu)先級,是右括號或者優(yōu)先級低于棧頂符號(乘除優(yōu)先加減,)
則棧頂元素依次出棧并輸出,并將當(dāng)前符號進(jìn)棧,一直到最終輸出后綴表達(dá)式為止。
?
中綴、轉(zhuǎn)后綴規(guī)則分析
?
?
首先判斷字符是否是數(shù)字
?
中綴、轉(zhuǎn)后綴函數(shù)局部代碼
將用戶輸入放到一個字符串,將轉(zhuǎn)換得到后綴表達(dá)式同樣放到一個字符串中,方便封裝進(jìn)行復(fù)用。
?
/* 將中綴表達(dá)式轉(zhuǎn)成后綴表達(dá)式 */ char* MidExpToAfterExp(const char* midExp) {//后綴表達(dá)式char* afterExp = (char*)malloc(sizeof(char)*EXPRESS_MAX);memset(afterExp, 0, EXPRESS_MAX);int j = 0;//afterExp下標(biāo)int k = 0;//preExp下標(biāo)SeqStack stack;// + - * / ( )符號棧InitStack(&stack);char numBuf[10] = { 0 };//連續(xù)的數(shù)字不能超過10位,也就是中綴表達(dá)式中數(shù)字不能超過10位char ch = 0;int numIndex = 0;//numBuf 下標(biāo)while (midExp[k]){ch = midExp[k++];//忽略中綴表達(dá)式中的空格if (ch == ' '){continue;}//回車代表中綴輸入完畢if ('\n' == ch){break;}//1、若是數(shù)字就輸出if (ch >= '0' && ch <= '9'){//如果輸入連續(xù)的數(shù)字,不是連續(xù)的數(shù)字 循環(huán)完畢 會走 2、非數(shù)字while (((ch >= '0' && ch <= '9') || '.' == ch) && numIndex < 10){numBuf[numIndex++] = ch;afterExp[j++] = ch;ch = midExp[k++];}numBuf[numIndex] = 0;afterExp[j++] = ' ';}//回車代表中綴輸入完畢if ('\n' == ch){break;}//忽略中綴表達(dá)式中的空格else if (' ' == ch){continue;}//2、非數(shù)字else if (ch < '0' || ch > '9'){numIndex = 0;//進(jìn)入這個if 數(shù)字肯定不連續(xù)了,下標(biāo)重置為0//右括號一定彈棧if (')' == ch){int flag = 1;//判斷中綴表達(dá)式中括號是否匹配,如果成對出現(xiàn)while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){flag = 0;//走到這里說明是()括號成對出現(xiàn)break;}afterExp[j++] = ch;afterExp[j++] = ' ';}if (flag){printf("中綴表達(dá)式輸入錯誤\n");exit(0);}}// + - 符號是優(yōu)先級最低的,一定是先依次彈棧再壓棧。else if ('+' == ch || '-' == ch){EleType top;GetTop(&stack, &top);//棧空或者棧頂為左括號 直接壓棧if (IsEmptyStack(&stack)|| '(' == top){push(&stack, ch);}else{char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){//不是因?yàn)?右括號而彈棧,多彈的(左括號壓回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}}// * / 符號優(yōu)先級只比 + -高,棧空或棧頂為(+-符號棧才直接壓棧,其他情況先依次彈棧再壓棧else if ('*' == ch || '/' == ch){EleType top;GetTop(&stack, &top);//棧空或者棧頂為左括號同樣直接壓棧if (IsEmptyStack(&stack) || '(' == top || '-' == top || '+' == top){push(&stack, ch);}else if ('*' == top || '/' == top){char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch || '-' == ch || '+' == ch){//不是因?yàn)?右括號而彈棧 * / 優(yōu)先級高于棧頂 + - 就不彈棧了,多彈的壓回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}} else if ( '(' == ch){push(&stack, ch);}else{printf("中綴表達(dá)式輸入錯誤\n");exit(0);}}}//符號棧內(nèi)容不為空 依次出棧并打印while (!IsEmptyStack(&stack)){pop(&stack, &ch);afterExp[j++] = ch;afterExp[j++] = ' ';}return afterExp; }?
?
?
?
?
?
完整代碼
?
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define STACK_INIT_SIZE 20 // 棧初始容量 #define STACK_INCREMENT 10 //棧滿后,每次擴(kuò)充的容量 #define EXPRESS_MAX 1024 //后綴表達(dá)式 長度不能超過1024 typedef int Status; typedef char EleType;typedef struct SeqStack {EleType* top;//棧頂指針EleType* base;//棧底指針int stackSize;//棧容量 }SeqStack; //初始化棧 Status InitStack(SeqStack* stack) {//開辟空間stack->base = stack->top = (EleType*)malloc(STACK_INIT_SIZE * sizeof(EleType));if (!stack->base){exit(0);}stack->stackSize = STACK_INIT_SIZE;return OK; } //壓棧 Status push(SeqStack* stack, EleType e) {if (stack == NULL){return ERROR;}//壓棧之前檢測容量是否足夠if (stack->top - stack->base == stack->stackSize){//超出容量 進(jìn)行擴(kuò)容,使用realloc函數(shù),會拷貝原內(nèi)存內(nèi)容stack->base = (EleType*)realloc(stack->base, stack->stackSize + STACK_INCREMENT);if (!stack->base){exit(0);}stack->top = stack->base + stack->stackSize;stack->stackSize += STACK_INCREMENT;}*stack->top = e;stack->top++;return OK; } //彈棧 Status pop(SeqStack* stack, EleType *e) {if (stack == NULL || e == NULL){return ERROR;}//空棧if (stack->top == stack->base){return ERROR;}*stack->top--;*e = *stack->top;return OK; } /* 獲取棧頂元素 */ Status GetTop(SeqStack* stack, EleType *e) {if (NULL == stack) {return ERROR;}*e = *(stack->top - 1);return OK; } /* 判斷棧是否為空 */ int IsEmptyStack(SeqStack* stack) {if (NULL == stack) {return ERROR;}if (stack->top == stack->base) {return TRUE;}return FALSE; } /* 銷毀棧 */ Status DestroyStack(SeqStack* stack) {if (NULL == stack) {return ERROR;}//銷毀棧 是釋放棧在內(nèi)存中占用的空間資源if (!stack->base){free(stack->base);}stack->top = stack->base = NULL;stack->stackSize = 0;return OK; } /* 將中綴表達(dá)式轉(zhuǎn)成后綴表達(dá)式 */ char* MidExpToAfterExp(const char* midExp) {//后綴表達(dá)式char* afterExp = (char*)malloc(sizeof(char)*EXPRESS_MAX);memset(afterExp, 0, EXPRESS_MAX);int j = 0;//afterExp下標(biāo)int k = 0;//preExp下標(biāo)SeqStack stack;// + - * / ( )符號棧InitStack(&stack);char numBuf[10] = { 0 };//連續(xù)的數(shù)字不能超過10位,也就是中綴表達(dá)式中數(shù)字不能超過10位char ch = 0;int numIndex = 0;//numBuf 下標(biāo)while (midExp[k]){ch = midExp[k++];//忽略中綴表達(dá)式中的空格if (ch == ' '){continue;}//回車代表中綴輸入完畢if ('\n' == ch){break;}//1、若是數(shù)字就輸出if (ch >= '0' && ch <= '9'){//如果輸入連續(xù)的數(shù)字,不是連續(xù)的數(shù)字 循環(huán)完畢 會走 2、非數(shù)字while (((ch >= '0' && ch <= '9') || '.' == ch) && numIndex < 10){numBuf[numIndex++] = ch;afterExp[j++] = ch;ch = midExp[k++];}numBuf[numIndex] = 0;afterExp[j++] = ' ';}//回車代表中綴輸入完畢if ('\n' == ch){break;}//忽略中綴表達(dá)式中的空格else if (' ' == ch){continue;}//2、非數(shù)字else if (ch < '0' || ch > '9'){numIndex = 0;//進(jìn)入這個if 數(shù)字肯定不連續(xù)了,下標(biāo)重置為0//右括號一定彈棧if (')' == ch){int flag = 1;//判斷中綴表達(dá)式中括號是否匹配,如果成對出現(xiàn)while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){flag = 0;//走到這里說明是()括號成對出現(xiàn)break;}afterExp[j++] = ch;afterExp[j++] = ' ';}if (flag){printf("中綴表達(dá)式輸入錯誤\n");exit(0);}}// + - 符號是優(yōu)先級最低的,一定是先依次彈棧再壓棧。else if ('+' == ch || '-' == ch){EleType top;GetTop(&stack, &top);//棧空或者棧頂為左括號 直接壓棧if (IsEmptyStack(&stack)|| '(' == top){push(&stack, ch);}else{char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch){//不是因?yàn)?右括號而彈棧,多彈的(左括號壓回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}}// * / 符號優(yōu)先級只比 + -高,棧空或棧頂為(+-符號棧才直接壓棧,其他情況先依次彈棧再壓棧else if ('*' == ch || '/' == ch){EleType top;GetTop(&stack, &top);//棧空或者棧頂為左括號同樣直接壓棧if (IsEmptyStack(&stack) || '(' == top || '-' == top || '+' == top){push(&stack, ch);}else if ('*' == top || '/' == top){char cur = ch;while (!IsEmptyStack(&stack)){pop(&stack, &ch);if ('(' == ch || '-' == ch || '+' == ch){//不是因?yàn)?右括號而彈棧 * / 優(yōu)先級高于棧頂 + - 就不彈棧了,多彈的壓回去push(&stack, ch);break;}afterExp[j++] = ch;afterExp[j++] = ' ';}push(&stack, cur);}} else if ( '(' == ch){push(&stack, ch);}else{printf("中綴表達(dá)式輸入錯誤\n");exit(0);}}}//符號棧內(nèi)容不為空 依次出棧并打印while (!IsEmptyStack(&stack)){pop(&stack, &ch);afterExp[j++] = ch;afterExp[j++] = ' ';}return afterExp; }int main(int argc, char *argv[]) {while (1){printf("請輸入中綴表達(dá)式(#表示退出):");//中綴表達(dá)式char* midExp = (char*)malloc(sizeof(char)*EXPRESS_MAX) ;memset(midExp, 0, EXPRESS_MAX);fgets(midExp, 1024, stdin);//midExp 包含換行符if ('#' == midExp[0]){break;}//后綴表達(dá)式char* afterExp= MidExpToAfterExp(midExp);printf("對應(yīng)的后綴表達(dá)式:%s\n", afterExp);}return 0; }?
?
?
?
?
?
?
驗(yàn)證結(jié)果
進(jìn)行復(fù)雜性驗(yàn)證哈,確保程序正確性。如何驗(yàn)證正確性呢?請看 后綴表達(dá)式運(yùn)算規(guī)則,如果根據(jù)后綴表達(dá)式 的計(jì)算結(jié)果和中綴表達(dá)式計(jì)算結(jié)果一致就說明轉(zhuǎn)換正確。如果不正確,你來找我。
?
?
總結(jié)
以上是生活随笔為你收集整理的栈应用:中缀表达式转后缀表达式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: io异常
- 下一篇: react-draft-wysiwyg富