表達式樹:
葉子是操作數,其余結點為操作符,是二叉樹的其中一種應用
====================我是分割線======================
一棵表達式樹如下圖:
1 struct TreeNode { 2 object element; 3 TreeNode* leftChild; 4 TreeNode* rightChild; 5 };
用後綴表達式構建一棵表達式樹:
思路:(與後綴表達式計算四則運算結構相似)
1. 一一讀入輸入字符串
2. 若是操作數,則初始化為結點後入棧
3. 若是操作符,則從棧中彈出兩個結點(新結點的左右子樹),與剛讀入的操作符結合起來構建新結點,然後入棧
重復1~3,最後棧內有一棵表達式樹的root結點
code實現:
1 #include<iostream> 2 #include <string> 3 #include<stack> 4 5 using namespace std; 6 7 struct TreeNode{ 8 char element; 9 TreeNode* leftChild; 10 TreeNode* rightChild; 11 TreeNode(char ch, TreeNode* l, TreeNode* r) { 12 element = ch; 13 leftChild = l; 14 rightChild = r; 15 } 16 TreeNode() { 17 element = '0'; 18 leftChild = 0; 19 rightChild = 0; 20 } 21 }; 22 23 //測試函數——輸出樹 24 void drawTree(TreeNode* root, bool infix) { 25 if (infix) { 26 if (root) { 27 //中序遍歷 28 drawTree(root->leftChild, infix); 29 cout << root->element; 30 drawTree(root->rightChild, infix); 31 } 32 else return; 33 } 34 else { 35 if (root) { 36 //後序遍歷 37 drawTree(root->leftChild, infix); 38 drawTree(root->rightChild, infix); 39 cout << root->element; 40 } 41 else return; 42 } 43 } 44 45 int main() { 46 string input; 47 stack<TreeNode> expressionTree; 48 while (cin >> input) { 49 if (input == "0") break; 50 for (int i = 0; i < input.size();) { 51 char ch = input[i++]; 52 if (ch >= '0' && ch <= '9') { 53 TreeNode leaves; 54 leaves.element = ch; 55 expressionTree.push(leaves); 56 } 57 else { 58 //出棧,成為新結點右子樹 59 TreeNode* right = new TreeNode(expressionTree.top().element, expressionTree.top().leftChild, expressionTree.top().rightChild); 60 expressionTree.pop(); 61 62 ////出棧,成為新結點左子樹 63 TreeNode* left = new TreeNode(expressionTree.top().element, expressionTree.top().leftChild, expressionTree.top().rightChild); 64 expressionTree.pop(); 65 66 //新結點入棧 67 TreeNode leave(ch, left, right); 68 expressionTree.push(leave); 69 } 70 } 71 TreeNode* root = &expressionTree.top(); 72 expressionTree.pop(); 73 drawTree(root, true); 74 } 75 return 0; 76 } 77 78 //NULL 與 0 的概念
局限性:
1. 假設所有輸入合法,無空格等非法符號輸入
2. 測試輸出函數不能還原優先級,12+3* 的表達式樹測試輸出將是 1+2*3,而並非(1+2)*3,如果需要,可以在結構體中再加上一個優先級判斷,若子結點的操作符優先級小於父結點,則輸出時子樹的表達式需要最後要整體放到一個括號內。
一些bugs:
關於NULL、0 和 nullptr的學習:
1. NULL是宏
2. C中對於NULL的定義為 #define NULL ((void *)0)
3. C++中對於NULL的定義為0
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
4. C++11中對於nullptr的定義
1 const 2 class nullptr_t 3 { 4 public: 5 template<class T> 6 inline operator T*() const 7 { return 0; } 8 9 template<class C, class T> 10 inline operator T C::*() const 11 { return 0; } 12 13 private: 14 void operator&() const; 15 } nullptr = {};
5. 由於C++中的定義,在重載函數時容易出錯
1 //NULL 0 nullptr 2 #include <iostream> 3 #include <stdio.h> 4 5 using namespace std; 6 7 int f(void* ptr) { 8 return 2; 9 } 10 11 int f(int num) { 12 return 3; 13 } 14 15 int main() { 16 int result1 = f(0); 17 //int result2 = f(NULL); 18 int result3 = f(nullptr); 19 cout << "result1 = " << result1 << endl; 20 //cout << "result2 = " << result2 << endl; 21 cout << "result3 = " << result3 << endl; 22 return 0; 23 }
當我把17行的注釋符去掉時:編譯錯誤
最後運行的結果如下:
說明C++11標准中,nullptr的調用在重載時不會又歧義,而0則會在重載時調用int形參的函數
在C++中,可以的話,盡量用nullptr為空指針賦值
文章推薦:
http://www.cppblog.com/airtrack/archive/2012/09/16/190828.html