二叉树遍历方式总结

二叉树遍历方式总结

1
2
3
4
5
6
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

1
2
3
4
5
6
void preorder(TreeNode* root, vector<int>& res) {
    if (!root) return;
    res.push_back(root->val);    // 根
    preorder(root->left, res);   // 左
    preorder(root->right, res);  // 右
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
vector<int> preorderTraversal(TreeNode* root) {
    vector<int> 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);
    }
    return res;
}

1
2
3
4
5
6
void inorder(TreeNode* root, vector<int>& res) {
    if (!root) return;
    inorder(root->left, res);    // 左
    res.push_back(root->val);    // 根
    inorder(root->right, res);   // 右
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
vector<int> inorderTraversal(TreeNode* root) {
    vector<int> res;
    stack<TreeNode*> st;
    TreeNode* cur = root;

    while (cur || !st.empty()) {
        // 一路往左走,全部压栈
        while (cur) {
            st.push(cur);
            cur = cur->left;
        }
        // 弹出最左节点
        cur = st.top();
        st.pop();
        res.push_back(cur->val);
        // 处理右子树
        cur = cur->right;
    }
    return res;
}

BST 中序遍历 = 升序序列,这是二叉搜索树的重要性质。


1
2
3
4
5
6
void postorder(TreeNode* root, vector<int>& res) {
    if (!root) return;
    postorder(root->left, res);   // 左
    postorder(root->right, res);  // 右
    res.push_back(root->val);     // 根
}

前序是「根左右」,改成「根右左」再翻转 = 「左右根」= 后序

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
vector<int> postorderTraversal(TreeNode* root) {
    vector<int> 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->left) st.push(node->left);
        if (node->right) st.push(node->right);
    }
    reverse(res.begin(), res.end());  // 翻转得到左右根
    return res;
}

用队列,一层一层输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if (!root) return res;

    queue<TreeNode*> q;
    q.push(root);

    while (!q.empty()) {
        int size = q.size();  // 当前层的节点数
        vector<int> level;
        for (int i = 0; i < size; i++) {
            TreeNode* node = q.front();
            q.pop();
            level.push_back(node->val);
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
        res.push_back(level);
    }
    return res;
}

利用叶子节点的空指针,不用栈,空间复杂度 O(1)。

中序 Morris 遍历核心思路:

  1. 如果左孩子为空,输出当前节点,去右孩子
  2. 如果左孩子不为空,找到左子树的最右节点(前驱)
    • 前驱右指针为空:指向当前节点,当前节点去左孩子
    • 前驱右指针指向当前节点:说明第二次访问,输出,恢复空指针,去右孩子
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vector<int> morrisInorder(TreeNode* root) {
    vector<int> res;
    TreeNode* cur = root;

    while (cur) {
        if (!cur->left) {
            res.push_back(cur->val);
            cur = cur->right;
        } else {
            TreeNode* prev = cur->left;
            while (prev->right && prev->right != cur) {
                prev = prev->right;
            }
            if (!prev->right) {
                prev->right = cur;
                cur = cur->left;
            } else {
                prev->right = nullptr;
                res.push_back(cur->val);
                cur = cur->right;
            }
        }
    }
    return res;
}

遍历方式顺序递归迭代应用场景
前序根左右✅ 简单栈复制树、前缀表达式
中序左根右✅ 简单栈BST 升序输出
后序左右根✅ 简单栈(翻转法)删除树、后缀表达式
层序逐层—队列求深度、按层处理
Morris中序—无额外空间空间严格受限

递归三件套:

1
2
3
4
终止条件:if (!root) return;
处理根:res.push_back(root->val);
递归左:dfs(root->left);
递归右:dfs(root->right);

三个位置换顺序就是三种遍历。