中綴表示式生成二叉樹並利用字尾表示式進行求值運算
這次是某人的課程作業,題目不難,但是很複雜
原題如下
以字元序列的形式從鍵盤輸入不含變數的整數算術四則表示式(可以有小括號);
檢查表示式的正確性
將其轉換為二叉樹的儲存表示;
通過後序遍歷得到其後綴表示式序列,輸出該序列;
利用字尾表示式進行求值運算,輸出求值結果
原本按照我的思路,先求字尾表示式在求值與生成樹,不過既然題目這麼說了,就不得不按照題目要求去做......
1.表示式的正確性
原本的思路是做正則表示式,在利用包或者是自己寫一個自動機去實現,不過發現這裡面的正則表示式有一點小複雜.後來在網上找到了遞迴下降分析法的思路,就正好最近也在寫編譯原理的題目,剛好把詞法分析器辦過來用.
2.二叉樹生成
二叉樹的生成和字尾表示式的求值其實是很相似的,都是利用兩個棧,反覆比較兩個棧的內容,進行求值,只是一個是顯示數值,另外一個這是構造節點.在資料結構的書中講述過後綴表示式的演算法,在這裡就不贅述了
最後提供
#include <iostream> #include <vector> #include <string> #include <utility> #include<stack> using namespace std; enum Type { Other, Add, Sub, Mul, Div, Num, LetfBra, RightBra }; typedef pair<string, Type> Tocken; vector<Tocken> word; struct Node { string oper;//運算元或運算子 Node *left;//左子樹 Node *right;//右子樹 }; int idx = Other; Type sym; int err = 0; // 錯誤 void E(); void E1(); void T(); void T1(); void F(); void PutIn(string& expr); bool isOper(char op) { return op == '+' || op == '-' || op == '*' || op == '/' || op == '(' || op == ')'; } //求運算子的優先順序 int getOperPri(char op) { switch (op) { case '(': return 1; break; case '+': case '-': return 2; break; case '*': case '/': return 3; break; default: return 0; } } //銷燬二叉樹 void freeTree(Node*& p) { if (p->left != NULL) freeTree(p->left); if (p->right != NULL) freeTree(p->right); delete(p); } //表示式生成二叉樹 void generateTree(Node*& p, vector<Tocken> WordArray) { stack <char> operStack; stack <Node*> dataStack; char c; vector<Tocken>::iterator tmpite = WordArray.begin(); while (tmpite != WordArray.end() || operStack.size() != 0) { if (tmpite != WordArray.end() && tmpite->second == 5)//是運算數字,則進運算元的棧 { p = new Node; p->oper = tmpite->first; p->left = NULL; p->right = NULL; dataStack.push(p); tmpite++; } else { if (tmpite != WordArray.end()){ switch (tmpite->first[0]) { case '('://進棧 operStack.push('('); tmpite++; break; case ')'://脫括號 while (true) { c = operStack.top(); operStack.pop(); if (c == '(') { break; } p = new Node; p->oper = c; p->left = NULL; p->right = NULL; if (dataStack.size()) { p->right = dataStack.top(); dataStack.pop(); } if (dataStack.size()) { p->left = dataStack.top(); dataStack.pop(); } dataStack.push(p); } tmpite++; break; default: if (operStack.size() == 0 || getOperPri(operStack.top()) < getOperPri(tmpite->first[0])) {//進棧 operStack.push(tmpite->first[0]); tmpite++; } else {//出棧 p = new Node(); p->oper = operStack.top(); p->left = NULL; p->right = NULL; if (dataStack.size()) { p->right = dataStack.top(); dataStack.pop(); } if (dataStack.size()) { p->left = dataStack.top(); dataStack.pop(); } dataStack.push(p); operStack.pop(); } break; } } else{ p = new Node(); p->oper = operStack.top(); p->left = NULL; p->right = NULL; if (dataStack.size()) { p->right = dataStack.top(); dataStack.pop(); } if (dataStack.size()) { p->left = dataStack.top(); dataStack.pop(); } dataStack.push(p); operStack.pop(); } } } p = dataStack.top(); dataStack.pop(); } void PutIn(string& expr) { cout << "輸入轉化的表示式\n"; cin >> expr; } bool AfterTraversal(Node* p, vector<string>& After) { if (NULL == p){ return false; } AfterTraversal(p->left, After); AfterTraversal(p->right, After); cout << p->oper << " "; After.push_back(p->oper); return true; } /*--------------------------------詞法分析----------------------------*/ bool word_analysis(vector<Tocken>& word, const string expr) { for (int i = 0; i<expr.length(); ++i) { // 如果是 + - * / ( ) if (expr[i] == '(' || expr[i] == ')' || expr[i] == '+' || expr[i] == '-' || expr[i] == '*' || expr[i] == '/') { string tmp; tmp.push_back(expr[i]); switch (expr[i]) { case '+': word.push_back(make_pair(tmp, Add)); break; case '-': word.push_back(make_pair(tmp, Sub)); break; case '*': word.push_back(make_pair(tmp, Mul)); break; case '/': word.push_back(make_pair(tmp, Div)); break; case '(': word.push_back(make_pair(tmp, LetfBra)); break; case ')': word.push_back(make_pair(tmp, RightBra)); break; } } // 如果是數字開頭 else if (expr[i] >= '1' && expr[i] <= '9') { string tmp; while (expr[i] >= '0' && expr[i] <= '9') { tmp.push_back(expr[i]); ++i; } word.push_back(make_pair(tmp, Num)); --i; } else { return false; } } return true; } /*--------------------------------語法分析----------------------------*/ // 讀下一單詞的種別編碼 void Next() { if (idx < word.size()) sym = word[idx++].second; else sym = Other; } // E → TE' void E() { T(); E1(); } // E' → +TE' | -TE' | ε void E1() { if (sym == 1) { Next(); T(); E1(); } else if (sym == 2) { Next(); T(); E1(); } else if (sym != 7 && sym != 0) { err = -1; } } // T → FT' void T() { F(); T1(); } // T' → *FT' | /FT' | ε void T1() { if (sym == 3) { Next(); F(); T1(); } else if (sym == 4) { Next(); F(); T1(); } else if (sym != 1 && sym != 2 && sym != 7 && sym != 0) { err = -1; } } // F → (E) | d void F() { if (sym == 5) { Next(); } else if (sym == 6) { Next(); E(); if (sym == 7) { Next(); } else { err = -1; } } else { err = -1; } } int prior(char c) { switch (c) { case '+': case '-': return 1; case '*': case '/': return 2; default: return 0; } } bool isOperator(char c) { switch (c) { case '+': case '-': case '*': case '/': return true; default: return false; } } // 從棧中連續彈出兩個運算元 void popTwoNumbers(stack<int>& s, int& first, int& second) { first = s.top(); s.pop(); second = s.top(); s.pop(); } // 計算字尾表示式的值 int expCalculate(const vector<string>& postfix) { int first, second; stack<int> s; for (int i = 0; i<postfix.size(); ++i) { string c = postfix[i]; switch (c[0]) { case '+': popTwoNumbers(s, first, second); s.push(second + first); break; case '-': popTwoNumbers(s, first, second); s.push(second - first); break; case '*': popTwoNumbers(s, first, second); s.push(second*first); break; case '/': popTwoNumbers(s, first, second); s.push(second / first); break; default: s.push(atoi(c.c_str())); break; } } int result = s.top(); s.pop(); return result; } int main() { string expr; PutIn(expr); vector<string> After; Node* p = new Node(); if (!word_analysis(word, expr)){ cout << "輸入一個錯誤的表示式" << endl; } else { Next(); E(); if (sym == 0 && err == 0){ // 注意要判斷兩個條件 cout << "表示式正確" << endl; generateTree(p,word); AfterTraversal(p, After); cout << endl; cout << "值為:"<< expCalculate(After); } else cout << "輸入錯誤的表示式" << endl; } return 0; }
原始碼(ps.因為是按模組組合寫的,可能有一些函式會有重複,大家看的時候見諒)
相關推薦
中綴表示式生成二叉樹並利用字尾表示式進行求值運算
這次是某人的課程作業,題目不難,但是很複雜 原題如下 以字元序列的形式從鍵盤輸入不含變數的整數算術四則表示式(可以有小括號); 檢查表示式的正確性 將其轉換為二叉樹的儲存表示; 通過後序遍歷得到其後綴表示式序列,輸出該序列; 利用字尾表示式進行求值運算,
【資料結構學習筆記】——根據中綴表示式構建二叉樹並輸出
要求 輸入一箇中綴表示式,構造表示式樹,以文字方式輸出樹結構。 輸入:例如,輸入a+b+c*(d+e) 輸出:以縮排表示二叉樹的層次,左(根),右(葉),上(右子樹),下(左子樹) 分析 我們有兩個核心的問題需要解決,一是如何按照中綴表示式來
C++實現利用(前序和中序生成二叉樹)以及(二叉樹的鏡像)
lse pub 非遞歸 ace 方法 [] reorder spa push #include<iostream> #include<string.h> #include<stack> using namespace std; type
【資料結構週週練】015 利用遞迴演算法建立鏈式儲存的二叉樹並轉換左右孩子結點
一、前言 哈哈,今天就是程式設計師節啦,祝大家1024程式設計師節快樂。 今天要給大家分享的演算法是交換二叉樹是的左右孩子結點,比較簡單,需要建立一個結點用來暫存左孩子結點,下面給大家送上程式碼。 二、題目 將下圖用二叉樹存入,並交換二叉樹是的左右孩子結點。其中圓角矩形內為結點資
先序表示式恢復成二叉樹並計算--For初學者
思路是這樣的:首先,將先序表示式轉化成二叉樹,其次,用後序來遍歷二叉樹,最後,通過後序遍歷二叉樹的結果來計算最終結果。 那麼問題來了,為什麼我們要通過後序表示式來計算最終結果。這是因為後序表示式我們計算過,點選這裡,所以,我們先把後序表示式的程式碼放進.h的檔案
java建立二叉樹並遍歷
java在實現非遞迴先根,中根,後根遍歷時需要用到鏈棧Linkstack類,實現非遞迴層次遍歷需要用到鏈佇列Linkqueue類,前面文章已經實現。 下面實現二叉鏈式儲存結構 package practice3; public class bitreeNode { private
二叉樹輸入前序遍歷,中序遍歷重建二叉樹並返回
function reConstructBinaryTree(pre, vin) { if(pre.length===0||!pre){ return; }
按層遍歷二叉樹並列印換行
package com.zyl.algorithm; import java.util.LinkedList; public class PrintBinaryTreeByFloor { publ
[原始碼和文件分享]構造二叉樹並遍歷
介紹 已知二叉樹的後序遍歷和中序遍歷序列,構造對應的二叉樹,並非遞迴前序遍歷該二叉樹。 1 解題思路 先建立一個結構體,結構體中包含資料域以及左孩子和右孩子的指標域。然後首先輸入中序遍歷和後序遍歷的陣列,再定義四個變數:il,ir,pl,pr即中序遍歷的左右端點和後序遍歷的左右端點。然後
javascript生成二叉樹, 以及其前中後序遍歷
序言 最近看了些面試題, 發現大多數都會問一個問題就是JavaScript生成二叉樹, 本來想偷懶百度看看算了, 可是發現好多網站部落格的程式碼都是一樣的, 並且生成的還是平衡二叉樹………. 如果我不輸入數字你給我生成一個試試. so, 看起來只能自己搞一下了. 百度百科–平衡二
jS生成二叉樹,二叉樹的遍歷,查詢以及插入
js遞迴,二叉樹的操作 //遞迴演算法n次冪 function foo(n) { if (n == 1) { return 1; } else { return n * foo(n - 1); } } //console.log(foo(3)
二叉樹的簡單應用--表示式樹
表示式樹 算數表示式是分層的遞迴結構,一個運算子作用於相應的運算物件,其運算物件又可以是任意複雜的表示式。二叉樹的遞迴結構正好用來表示這種表示式。下面只討論二元表示式。 二元表示式可以很自然的聯絡到二叉樹:以基本運算物件作為葉節點中的資料;以運算子作為非葉節
已知一個按先序序列輸入的字元序列,如abc,,de,g,,f,,,(其中逗號表示空節點)。請建立二叉樹並按中序和後序方式遍歷二叉樹,最後求出葉子節點個數和二叉樹深度。
這是一個標準的模板題 記下了就完事了! Input 輸入一個長度小於50個字元的字串。 Output 輸出共有4行: 第1行輸出中序遍歷序列; 第2行輸出後序遍歷序列; 第3行輸出葉子節點個數; 第4行輸出二叉樹深度。 Sample Input abc,,
Java 通過先序中序序列生成二叉樹
題目 二叉樹的前序以及後續序列,以空格間隔每個元素,重構二叉樹,最後輸出二叉樹的三種遍歷方式的序列以驗證。 輸入: 1 2 3 4 5 6 7 8 9 10 3 2 5 4 1 7 8 6 10 9 輸出: 1,2,3,4,5,6,7,8,9,10
已知二叉樹的前序和中序序列,構建二叉樹並求後序序列,java實現。
已知二叉樹的前序和中序序列,或者已知二叉樹的後序和中序序列,是能夠唯一確定一棵二叉樹的。但是如果僅知道二叉樹的前序和後序序列,一般是不能唯一確定一棵二叉樹的,但是可以分析有多少種可能的二叉樹,這個沒有具體研究,只知道節點少的情況還能湊合分析出來,但是節點多的情況下可能性太多
建立排序二叉樹並中序遍歷
分析:中序遍歷也叫中根遍歷,顧名思義是把根節點放在中間來遍歷,其遍歷順序為左子節點–>根節點–>右子節點。 方法一: #include<iostream> using nam
資料結構--非遞迴遍歷二叉樹(利用輔助棧)
#include "StdAfx.h" #include <stdio.h> #include <stdlib.h> /*非遞迴方法前序遍歷二叉樹,利用輔助棧(指標陣列實現)。由於對指標不是很熟悉,程式碼較為混亂,基本上實現遍歷的功能。
層序生成二叉樹
//假設節點的元素值均為整數,空節點的值為0 //注意,每個 非空節點 的孩子 都要寫出,否則程式無法結束 //下圖的樹,輸入為1 2 3 0 4 5 0 0 0 0 0 ^Z(windows程式結束標誌) #include <stdio.h> #include
第六章樹和二叉樹作業1—二叉樹--計算機17級 6-1 求二叉樹高度 (20 分)
6-1 求二叉樹高度 (20 分) 本題要求給定二叉樹的高度。 函式介面定義: int GetHeight( BinTree BT ); 其中BinTree結構定義如下: typedef struct TNode *Position; typedef P
3.6 在二叉樹中找到累加和為指定值的最長路徑長度
【題目】: 給定一棵二叉樹的頭節點head和一個32位整數sum,二叉樹節點值型別為整型,求累加和為sum的最長路徑長度。路徑是指從某個節點往下,每次最多選擇一個孩子節點或者不選所形成的的節點鏈 例如, 二叉樹如圖所示 -3 3 &