日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

前、中、后缀表达式概述及转换+栈的计算器原理及代码分析(含完整源码)

發布時間:2024/10/14 编程问答 85 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前、中、后缀表达式概述及转换+栈的计算器原理及代码分析(含完整源码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄:
1.前中后綴表達式的概述
2.中序表達式轉前后綴表達式
3.運用棧的后綴表達式實現計算器原理步驟
4.代碼實現和分析

1.前中后綴表達式的概述及相互轉換

  • 前綴表達式:運算符位于操作數之前。
  • 中綴表達式(波蘭式):首先前中后綴表達式,一般正常寫的(2*4-1)+5-6這種式子稱為中綴表達式。
  • 后綴表達式(逆波蘭式):運算符位于操作數之前。

    我們平時所看到的中綴表達式,計算機是不能直接拿來運算的,因為計算機不知道該如何計算,然而計算機能知道該如何計算前后綴表達式。這就是前后綴表達式的意義

    前綴和后綴表達式中是不含括號的

    2.中序表達式轉前后綴表達式

    2.1中綴表達式轉后綴表達式

    其實轉換的原理就是:

    從左到右依次遍歷每個數字和字符,若是數字就輸出,成為后綴表達式的一部分,若是符號,判斷與棧頂元素的優先級,是右括號或優先級不高于棧頂符號(乘除優先于加減)則棧頂元素依次出棧成為后綴表達式的一部分,再將當前符號進棧,直到最終后綴表達式輸出完畢。

    幾個注意點:

    • 同等級的運算符比如+,先進的+的優先級大于之后進棧的+優先級
    • 一個元素進棧,必須匹配優先級比自己低的元素才能進,否則比它高的符號都彈出來作為表達式的一部分自己再進棧,比如:棧有兩個元素,棧底為+,然后*在+上邊,那么此時-進棧,由于此時的+和 *的優先級都比-高,所以兩個都彈出來變成表達式的一部分自己再進棧
    • 左括號比所有括號外邊的符號優先級高,比括號里邊的所有符號都低
    • 當一個右括號進棧后,與自己最近的左括號之間的所有元素彈出成為表達式的一部分,然后左右括號抵消
    舉個例子(S1是存放運算符的棧,S2是存放生成的后綴表達式的棧):

    2.2中綴表達式轉前綴表達式:

    其實和前面差不多,和轉后綴表達式有五個不同點

    • 中綴表達式轉前綴表達式是自右向左掃描的
    • 右括號比所有括號外邊的符號優先級高,比括號里邊的所有符號都低
    • 當一個左括號進棧后,與自己最近的右括號之間的所有元素彈出成為表達式的一部分,然后左右括號抵消
    • 中綴轉后綴還有一個不一樣的是,棧頂與當前遇到的新的運算符屬于同級運算符時,棧頂即要出棧,因為是同級先算左邊;然后中綴轉前綴由于是右到左遍歷的,所以同級運算符不出棧,因為出棧則代表最后的結果要先算右邊
    • 得到的表達式倒置就是我們需要的前綴表達式

    還拿1+((2+3)*4)-5舉例子:

    3.運用棧的后綴表達式實現計算器原理步驟

    3.1后綴表達式實現計算器原理

    程序初始化兩個棧,一個是OPTR(運算符棧),一個是OPND(操作數棧),然后掃描表達式,一個一個的讀入字符。在把我們輸入的中綴表達式裝換成后綴表達式的同時進行計算

    程序是如何邊轉換邊計算呢,比如9+(3-1)*3,我們從左到右掃描,那么OPTR和OPND兩個棧的元素變化如下

    掃描到的元素OPND棧OPTR棧
    99
    +9+
    (9+(
    393+(
    -93+(-
    1931+(-
    )92+
    *92+*
    3923+*
    無元素可以掃描96+
    無元素可以掃描15(最終結果)

    可以發現只要彈出一個運算符就會在操作數棧中彈出兩個操作數,先出來的在右后出來的在左,讓彈出來的運算符對兩個操作數進行計算,計算完畢后壓入操作數棧中

    3.2后綴表達式實現計算器原理的步驟

    我們的程序是不會知道你輸入的表達式是否開始和結束,那么此時我們使用#來表示輸入開始和結束,比如我們想計算2+2,那么就需要輸入2+2#(我們可以在初始化的時候把起始的#壓入運算符棧)然后回車,讓我們的程序計算。計算的過程是:程序初始化兩個棧,一個是OPTR(運算符棧),一個是OPND(操作數棧),然后掃描表達式,一個一個的讀入字符(我們把數字和操作符都看成字符),,如果表達式沒有掃描完畢(即沒有遇到#)或者說OPTR的棧頂元素不為#時則循環執行下面的操作:
    1.若字符不是運算符,則壓入OPND棧中,讀入下一個字符
    2.若字符是運算符則根據OPTR的棧頂元素和新掃描的字符的優先級比較結果,做不同的處理
    ? ?(1)若是小于,則ch壓入OPTR棧,再讀入下一個字符
    ? ?(2)若是大于,則彈出OPTR棧頂的運算符,從OPND棧彈出兩個數,進行相應運算,結果壓入OPND棧
    ? ?(3)若是等于,則OPTR的棧頂元素是“(”且新掃描的字符為“)”,這時彈出OPTR棧頂的“(”相當于括號匹配成功,然后讀入下一個字符

    4. 代碼實現和分析

    #include<stdio.h> const char oper[7] = { '+', '-', '*', '/', '(', ')', '#' }; #define OK 1 #define ERROR 0 #define OVERFLOW -2 typedef char SElemType; typedef int Status; typedef struct SNode {int data;struct SNode *next; } SNode, *LinkStack;//構造一個空棧 Status InitStack(LinkStack &S) {S = NULL;return OK; }//判斷是否為空棧 bool StackEmpty(LinkStack S) {if (!S)return true;return false; }//用e返回S的項元素 Status GetTop(LinkStack &S) {if (!S)return ERROR;return S->data; }//插入e為新的項元素 Status Push(LinkStack &S, SElemType e) {SNode *p = new SNode;if (!p) {return OVERFLOW;}p->data = e;p->next = S;S = p;return OK; }//刪除S的項元素,并用e返回其值 Status Pop(LinkStack &S, SElemType &e) {SNode *p;if (!S)return ERROR;e = S->data;p = S;S = S->next;delete p;return OK; }/*判斷輸入的某個字符是否是運算符*ch表示輸入的字符*oper數組中存放系統能識別的運算符*/ bool In(char ch) {for (int i = 0; i < 7; i++) {if (ch == oper[i]) {return true;}}return false; }/*比較兩個運算符的優先級*a,b中存放待比較的運算符*/ char Precede(char a, char b) {if ((a == '(' && b == ')') || (a == '#' && b == '#')) {return '=';} else if (a == '(' || a == '#' || b == '(' || (a == '+' || a == '-') && (b == '*' || b == '/')) {return '<';} elsereturn '>'; }/*進行兩數的運算*a,b中分別以char型存放兩個待運算的操作數*theta中存放代表操作符的字符*結果以char型返回*/ char Operate(char a, char theta, char b) {switch (theta) {case '+':return (a - '0') + (b - '0') + 48;case '-':return (a - '0') - (b - '0') + 48;case '*':return (a - '0') * (b - '0') + 48;case '/':return (a - '0') / (b - '0') + 48;}return 0; }//算法3.22 表達式求值 char EvaluateExpression() {//算術表達式求值的算符優先算法,設OPTR和OPND分別為運算符棧和操作數棧LinkStack OPTR, OPND;char ch, theta, a, b, x, top;InitStack(OPND); //初始化OPND操作數棧InitStack(OPTR); //初始化OPTR運算符棧Push(OPTR, '#'); //將表達式起始符“#”壓入OPTR棧scanf("%c",&ch);while (ch != '#' || (GetTop(OPTR) != '#')) //表達式沒有掃描完畢或OPTR的棧頂元素不為“#”{if (!In(ch)) {Push(OPND, ch);scanf("%c",&ch);} //ch不是運算符則進OPND棧elseswitch (Precede(GetTop(OPTR), ch)) //比較OPTR的棧頂元素和ch的優先級{case '<': //棧頂元素優先級低Push(OPTR, ch);scanf("%c",&ch); //當前字符ch壓入OPTR棧,讀入下一字符chbreak;case '>':Pop(OPTR, theta); //彈出OPTR棧頂的運算符Pop(OPND, b);Pop(OPND, a); //彈出OPND棧頂的兩個運算數Push(OPND, Operate(a, theta, b)); //將運算結果壓入OPND棧break;case '=': //OPTR的棧頂元素是“(”且ch是“)”Pop(OPTR, x);scanf("%c",&ch); //彈出OPTR棧頂的“(”,讀入下一字符chbreak;} //switch} //whilereturn GetTop(OPND); //OPND棧頂元素即為表達式求值結果 }int menu() {int c;printf("0-9以內的多項式計算\n" );printf("1.計算\n");printf("0.退出\n");printf("選擇:");scanf("%d",&c);return c; }int main() {do{switch (menu()) {case 1: {printf("請輸入要計算的表達式(操作數和結果都在0-9的范圍內,以#結束):\n如 2+2# \n" );char res = EvaluateExpression();//算法3.22 表達式求值printf("計算結果為%d\n",res - 48);printf("--------------------------------------\n");}break;case 0:printf("退出成功\n");return 0;default:break;}}while (1);return 0; }

    例子:

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的前、中、后缀表达式概述及转换+栈的计算器原理及代码分析(含完整源码)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。