表達式樹是編譯器前端、計算器引擎、符號計算系統的核心資料結構。本文深度解析從後綴表達式(逆波蘭表示法)構建表達式樹的堆疊算法,提供完整 C++ 實現,並延伸討論樹的三種遍歷與表達式求值關係、編譯器應用場景、錯誤處理與擴展方向。
以表達式 (A + B) * (C + D) 為例,其表達式樹:


| 遍歷方式 | 順序 | 對應表達式 | 示例結果 |
|---|---|---|---|
| 前序 (Preorder) | 根 → 左 → 右 | 前綴表示法 (Prefix) | * + A B + C D |
| 中序 (Inorder) | 左 → 根 → 右 | 中綴表示法 (Infix,需括號) | (A + B) * (C + D) |
| 後序 (Postorder) | 左 → 右 → 根 | 後綴表示法 (Postfix/RPN) | A B + C D + * |
a b + c d e + * *Token: a Stack: [a]
Token: b Stack: [a, b]
Token: + Pop b, a → New(+) left=a, right=b → Push [+]
Token: c Stack: [+, c]
Token: d Stack: [+, c, d]
Token: e Stack: [+, c, d, e]
Token: + Pop e, d → New(+) left=d, right=e → Push [+, +]
Token: * Pop +, c → New(*) left=c, right=+ → Push [+, *]
Token: * Pop *, + → New(*) left=+, right=* → Push [*] ← 根節點
struct TreeNode {
char data; // 運算元或運算符
TreeNode* left;
TreeNode* right;
TreeNode(char ch) : data(ch), left(nullptr), right(nullptr) {}
};
TreeNode* buildExpressionTree(const string& postfix) {
stack<TreeNode*> st;
for (char ch : postfix) {
if (isspace(ch)) continue; // 跳過空白
TreeNode* node = new TreeNode(ch);
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
// 運算符:彈出兩個運算元
if (st.size() < 2) {
throw runtime_error("Invalid postfix: insufficient operands");
}
TreeNode* right = st.top(); st.pop();
TreeNode* left = st.top(); st.pop();
node->left = left;
node->right = right;
st.push(node);
} else {
// 運算元:直接壓入
st.push(node);
}
}
if (st.size() != 1) {
throw runtime_error("Invalid postfix: extra operands remain");
}
return st.top();
}
void deleteTree(TreeNode* root) {
if (root) {
deleteTree(root->left);
deleteTree(root->right);
delete root;
}
}
void preorder(TreeNode* root) {
if (root) {
cout << root->data << ' ';
preorder(root->left);
preorder(root->right);
}
}
void inorder(TreeNode* root) {
if (root) {
bool isOp = (root->data == '+' || root->data == '-' ||
root->data == '*' || root->data == '/');
if (isOp) cout << '(';
inorder(root->left);
cout << root->data << ' ';
inorder(root->right);
if (isOp) cout << ')';
}
}
void postorder(TreeNode* root) {
if (root) {
postorder(root->left);
postorder(root->right);
cout << root->data << ' ';
}
}
double evaluate(TreeNode* root, const unordered_map<char, double>& vars) {
if (!root) return 0;
char ch = root->data;
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
double left = evaluate(root->left, vars);
double right = evaluate(root->right, vars);
switch (ch) {
case '+': return left + right;
case '-': return left - right;
case '*': return left * right;
case '/': return right != 0 ? left / right : throw runtime_error("Divide by zero");
}
} else if (isdigit(ch)) {
return ch - '0'; // 單位數常數
} else {
auto it = vars.find(ch);
return (it != vars.end()) ? it->second : 0; // 變數查找
}
return 0;
}
int main() {
string postfix = "ab+cde+**"; // (a+b)*(c*(d+e))
try {
TreeNode* root = buildExpressionTree(postfix);
cout << "前序: "; preorder(root); cout << endl;
cout << "中序: "; inorder(root); cout << endl;
cout << "後序: "; postorder(root); cout << endl;
// 求值測試
unordered_map<char, double> vars = {{'a',2}, {'b',3}, {'c',4}, {'d',5}, {'e',6}};
// (2+3) * (4 * (5+6)) = 5 * 44 = 220
double result = evaluate(root, vars);
cout << "計算結果: " << result << endl;
deleteTree(root);
} catch (const exception& e) {
cerr << "錯誤: " << e.what() << endl;
}
return 0;
}
// 使用 string token 而非 char
vector<string> tokenize(const string& expr) {
// 處理多位數、變數名、浮點數、函數名等
// 正則或狀態機分割
}
| 運算符 | 優先級 | 結合性 | 節點屬性 |
|---|---|---|---|
() | 最高 | - | 分組,不入樹 |
^ | 4 | 右結合 | 冪運算 |
* / % | 3 | 左結合 | 乘除模 |
+ - | 2 | 左結合 | 加減 |
< > <= >= | 1 | 左結合 | 比較 |
class TreeVisitor {
public:
virtual void visit(TreeNode* node) = 0;
virtual ~TreeVisitor() = default;
};
void traverse(TreeNode* root, TreeVisitor* visitor) {
if (root) {
traverse(root->left, visitor);
traverse(root->right, visitor);
visitor->visit(root); // 後序訪問
}
}
// 具體訪問者:求值器、代碼生成器、優化器、打印器
從後綴表達式構建表達式樹是「堆疊 + 樹」雙重經典資料結構的完美結合。本文提供的算法邏輯清晰、代碼完整可編譯、錯誤處理完善,並延伸至求值、遍歷、編譯器應用等實戰場景。掌握此技術不僅能應對面試高頻題,更能深入理解編譯器前端、解釋器引擎、符號計算系統的核心運作機制。建議進一步實現:
表達式樹是連接高級語言語義與機器執行邏輯的關鍵橋樑,深入鑽研將受益匪淺。