給定二叉樹根節點,返回前序遍歷(根→左→右)節點值列表。要求非遞歸實現。
前序遍歷訪問節點後需先處理左子樹,右子樹暫存。利用棧後進先出特性:
cur 入棧前先訪問(加入結果)。cur 繼續循環。cur 為空時彈棧頂繼續。public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> st = new Stack<>();
TreeNode cur = root;
while (cur != null || !st.isEmpty()) {
while (cur != null) {
res.add(cur.val); // 訪問根
if (cur.right != null) // 右子節點入棧
st.push(cur.right);
cur = cur.left; // 轉向左子樹
}
if (!st.isEmpty())
cur = st.pop(); // 取出右子樹根
}
return res;
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
TreeNode* cur = root;
while (cur || !st.empty()) {
while (cur) {
res.push_back(cur->val);
if (cur->right) st.push(cur->right);
cur = cur->left;
}
if (!st.empty()) {
cur = st.top(); st.pop();
}
}
return res;
}
stack<TreeNode*> st;
if (root) st.push(root);
while (!st.empty()) {
TreeNode* node = st.top(); st.pop();
res.push_back(node->val);
if (node->right) st.push(node->right); // 先右後左
if (node->left) st.push(node->left);
}
此法將「訪問」與「展開子節點」合併,代碼更短,但需注意入棧順序相反。
| 方面 | 遞歸 | 顯式棧 |
|---|---|---|
| 代碼簡潔度 | 極高 | 中等 |
| 棧溢出風險 | 深樹有風險 | 可控(堆內存) |
| 中序/後序難度 | 低 | 需狀態標記或雙棧 |