引言

二叉树的遍历大体分为两种,深度优先广度优先,深度优先分为前中后序三种遍历方法,广度优先就是层序遍历;
我们都知道深度优先遍历是通过栈实现的,广度优先遍历是通过递归实现的;
这里分别用递归和迭代实现一下二叉树的三种深度优先遍历;

注:递归实现比较简单,就只列出核心部分

前序遍历

遍历顺序:中——左——右

递归实现:

void preTraversal(TreeNode* cur, vector<int>& vec) {
     if (cur == NULL) return;
     vec.push_back(cur->val);    // 中
     preTraversal(cur->left, vec);  // 左
     preTraversal(cur->right, vec); // 右
}

迭代实现:
这里需要注意一下左节点和右节点入栈的顺序,中间节点遍历除栈后,下一个遍历的就该是左节点,但是栈是先进后出,所以应该先让右节点入栈,然后左节点再入栈,这样就是左节点先遍历最后才是右节点;

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> sta;
        vector<int> result;
        if (root == NULL) return result;
        sta.push(root);
        while (!sta.empty()) {
            TreeNode* node = sta.top();                       // 中
            sta.pop();
            result.push_back(node->val);
            if (node->right) sta.push(node->right);           // 右(空节点不入栈)
            if (node->left) sta.push(node->left);             // 左(空节点不入栈)
        }
        return result;
    }
};

中序遍历

遍历顺序:左——中——右
递归实现:

void midTraversal(TreeNode* cur, vector<int>& vec) {
    if (cur == NULL) return;
    midTraversal(cur->left, vec);  // 左
    vec.push_back(cur->val);    // 中
    midTraversal(cur->right, vec); // 右
}

迭代实现:
中序实现和前序有些不同,先把根节点入栈,然后需要用一个指针一直遍历到左子树的最后一个节点,然后再依次出栈,再遍历右子树;
可以理解为指针帮忙访问节点,栈用来处理节点元素;

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> sta;
        TreeNode* cur = root;
        while (cur != NULL || !sta.empty()) {
            if (cur != NULL) { // 指针来访问节点,访问到最底层
                st.push(cur); // 将访问的节点放进栈
                cur = cur->left;                // 左
            } 
            else {
                cur = sta.top(); // 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
                sta.pop();
                result.push_back(cur->val);     // 中
                cur = cur->right;               // 右
            }
        }
        return result;
    }
};

后序遍历

递归实现:
遍历顺序:左——右——中

void postTraversal(TreeNode* cur, vector<int>& vec) {
    if (cur == NULL) return;
    postTraversal(cur->left, vec);  // 左
    postTraversal(cur->right, vec); // 右
    vec.push_back(cur->val);    // 中
}

迭代实现:
后序遍历其实和前序遍历很像,后序只需要把前序遍历中左右子树遍历顺序改一下,然后反转结果就可以了;

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> sta;
        vector<int> result;
        if (root == NULL) return result;
        sta.push(root);
        while (!st.empty()) {
            TreeNode* node = sta.top();
            sta.pop();
            result.push_back(node->val);
            if (node->left) sta.push(node->left); 
            if (node->right) sta.push(node->right); 
        }
        reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
        return result;
    }
};

总结

这几种遍历方法在二叉树中经常出现,而且也是二叉树的基础;我经常见到的还是递归,但是迭代也是需要掌握的,有的题目可能会有强制的要求;