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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

前缀表达式--转换+求值

發布時間:2024/1/1 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前缀表达式--转换+求值 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

到現在寫的比較多的是后綴表達式,然而到前綴表達式還沒什么思路
這里整理一下中綴表達式轉前綴表達式及前綴表達式的求值

中綴轉前綴

轉換原則

有個比較簡單的看法:(選擇題可以用)
將中綴表達式按計算順序加括號,前綴表達式則將括號中的運算符移到括號前面,后綴則移到后面,再將所有括號去掉即可
eg.

中綴表達式:a+b*c-(d+e) 所有運算單位加括號:((a+(b*c))-(d+e)) 1. 前綴表達式:把運算符號移動到對應的括號前面 變為:-( +(a *(bc)) +(de)) 把括號去掉:-+a*bc+de 前綴表達式出現 2. 后綴表達式:把運算符號移動到對應的括號后面 變為:((a(bc)* )+ (de)+ )- 把括號去掉:abc*+de+- 后綴表達式出現

注意要在運算符對應括號層級移動

實現思路

不同于后綴表達式,前綴表達式相當于倒著掃描(從右往左);且后綴表達式可以直接輸出,前綴要先放到棧里再彈出(實現翻轉)(即前綴出來首先是反著的)
先看一下轉前綴與轉后綴的對比,下面再仔細寫實現思路

從右往左掃描:

  • 若是操作數,直接放到棧prefix中
  • 若是操作符,如果符號棧為空,直接放入符號棧中;如果符號棧非空,則判斷當前棧頂元素
  • 若棧頂為“)”,直接將操作符壓入符號棧(從右往左掃描,先遇到的是右括號)
  • 若當前棧頂元素優先級>操作符優先級,棧頂元素移除,再比較移除后棧的棧頂元素優先級。直到棧頂元素優先級≤操作符,將操作符放入符號棧(NT:不同于后綴,這里是有等于,即等于時也先不輸出——>優先級等先輸出后面的)
  • 若遇到右括號,直接入棧
  • 若遇到左括號,將左右括號之間的符號全部移除到prefix中(左括號不入棧,注意最后將右括號彈出)
  • 重復1-4,直到最后一個字符被讀入
  • 判斷當前棧是否為空,若非空,將棧中元素依次移到prefix中
  • 依次彈出prefix棧(實現翻轉)
  • 代碼

    先轉一個后綴

    python

    from pythonds.basic.stack import Stackdef infixToPostfix(infixexpr):prec = {}prec["*"] = 3prec["/"] = 3prec["+"] = 2prec["-"] = 2prec["("] = 1opStack = Stack()postfixList = []tokenList = infixexpr.split()for token in tokenList:if token in "QWERTYUIOPASDFGHJKLZXCVBNM" or token in "1234567890":postfixList.append(token)elif token == '(': # 左括號直接壓入棧中opStack.push(token)elif token == ')': # 讀到右括號就把棧中的操作符彈出直到讀到(topToken = opStack.pop()while topToken != '(':postfixList.append(topToken)topToken = opStack.pop()else:while (not opStack.isEmpty()) and \(prec[opStack.peek()] >= prec[token]): # 只要棧里面的操作符比目前讀到的操作符優先級高,就優先輸出棧中的操作符postfixList.append(opStack.pop())opStack.push(token) # 將讀到的字符壓入棧中while not opStack.isEmpty(): # 將棧中的剩余字符全部彈出postfixList.append(opStack.pop())return " ".join(postfixList)print(infixToPostfix(input()))

    C++

    #include<bits/stdc++.h> using namespace std; int main() {string s;getline(cin,s);stack<char> mark;map<char,int> lst;lst['+'] = lst['-'] = 1;lst['*'] = lst['/'] = 2;bool flag=1;for(int i=0;i<s.length();i++){//先處理直接輸出的——數字if(isdigit(s[i]) || s[i]=='.' || ((!i||s[i-1]=='(') && (s[i]=='+' || s[i]=='-'))){if(!flag) cout << " ";else flag=0;if(s[i]!='+') cout << s[i];while(s[i+1]=='.' || isdigit(s[i+1]))cout << s[++i];}else{if(s[i]=='(') mark.push(s[i]);else if(s[i]==')'){while(!mark.empty()&&mark.top()!='('){cout << " " << mark.top();mark.pop();}mark.pop();}else if(mark.empty() || lst[s[i]]>lst[mark.top()]) mark.push(s[i]);else{while(!mark.empty()&&lst[mark.top()]>=lst[s[i]]){cout << " " << mark.top();mark.pop();}mark.push(s[i]);}}}while(!mark.empty()){cout << " " << mark.top();mark.pop();} }

    前綴

    正在調試中ing…

    前綴表達式求值

    💿 借題👉PTA

    基本想法

    最簡單的就像樣例中一樣,沒有小數和負數,先完成這個
    按剛剛實現的思路,求值也得是先求后面(倒著求)
    先跑到最里面——>堆棧 or 遞歸
    用遞歸實現起來更直觀(畢竟底層用的堆棧)

    #include<bits/stdc++.h> using namespace std; double exp() {char s[35];cin >> s;switch (s[0]){case '+':return exp() + exp();case '-': return exp() - exp();case '*': return exp() * exp();case '/':return exp() / exp();default:return atof(s);} } int main() {printf("%.1f\n",exp());return 0; }

    因為是前綴表達式,操作符肯定都在前面,因此把操作符——入棧
    若遇到數字,就取出一個操作符,兩個操作數進行處理了然后繼續循環,直到所有操作數處理完畢

    復雜情況

    完整思路:

  • 用數組s接受前綴表達式,連同空格一起
  • 將s全部壓入堆棧A中
  • 每次從堆棧A中取出一個字符x
  • 若是數字,看下一個字符y是數字還是空格
    • 若是空格,直接將x壓入棧B
    • 若是小數點,再取小數點下一個數,直到遇到空格,合并得到完整小數,壓入B
    • 若是數字,表示則表明x和y同為某一小數的小數部分,且y是x的前一位,則不斷循環,直到找到小數點,再加上小數點后面的數字,3者合并,得到一個完整的小數,然后壓入堆棧B中
  • 若是空格,忽略
  • 若是x運算符,則m=B.POP(),n=B.POP(),然后m,x,n運算,結果壓入B中
  • 總體來說,前綴表達式不用管優先級,遇到運算符就用

    寫了改改了不對不對又寫然后寫了好幾天的代碼……
    一開始是寫到小數點那整蒙了……

    想是要倒著運算那就從后往前遍歷
    將數字字符轉成對應數字
    但是問題是要是碰到不止一位數就要倒著X10相加,然后要是又是小數的話碰到小數點還得10的倒數再換……

    所以使代碼復雜的是獲取完整數字這一塊

    那就先從頭遍歷,截取完整的數字串,用stof轉換成小數存到棧里(非數字也直接入棧),然后出棧再算

    然后是日常糾結的代碼……

    #include<bits/stdc++.h> using namespace std; int main() {stack<double> st;string s,ss;getline(cin,s);vector<string> v;bool flag=true;for(int i=0;i<s.length();i++){int j=i;while(s[j]!=' ' && j<s.length())j++;ss = s.substr(i,j-i);v.push_back(ss);i=j;}for(int i=v.size()-1;i>=0;i--){ss=v[i];if(ss=="+" || ss=="-" || ss=="*" || ss=="/"){if(st.size()>=2){double a=st.top();st.pop();double b=st.top();st.pop();if(ss=="/"&&b==0){cout << "ERROR";flag=false;}else{if(ss=="+") st.push(a+b);else if(ss=="-") st.push(a-b);else if(ss=="*") st.push(a*b);else if(ss=="/") st.push(a/b);}}else{cout << "ERROR";flag=false;break;}}else{st.push(stof(ss));}}if(flag)printf("%.1f",st.top());return 0; }

    總結

    以上是生活随笔為你收集整理的前缀表达式--转换+求值的全部內容,希望文章能夠幫你解決所遇到的問題。

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