二叉树深度优先遍历总结

二叉树遍历是一个很常用的基础算法,尤其常用于作为递归转非递归算法的模板。其中,前序遍历常用作无返回值的自顶向下的递归算法的改写,后序遍历常用作带返回值的自底向上的递归算法的改写,例如求树的高度的两种思路。

这里对二叉树的非递归遍历做一个总结,前序、中序、后序使用的都是同一套模板。与递归写法一样,非递归写法也只有结点访问顺序的差别。

太长不看版(N-ary树更形象)

// 前序遍历
for (auto it=p->children.rbegin(); it != p->children.rend(); it++) {
    stk.emplace(*it, false);
}
stk.emplace(p, true);
// 后序遍历
stk.emplace(p, true);
for (auto&& it=p->children.rbegin(); it !=p->children.rend(); it++) {
    stk.emplace(*it, false);
}

递归遍历算法

前序遍历

vector<int> preorder(TreeNode* root, vector<int>& res) {
    if (!root) return res;
    res.push_back(root->val);
    preorder(root->left, res);
    preorder(root->right, res);
    return res;
}

中序遍历

vector<int> inorder(TreeNode* root, vector<int>& res) {
    if (!root) return res;
    inorder(root->left, res);
    res.push_back(root->val);
    inorder(root->right, res);
    return res;
}

后序遍历

vector<int> postorder(TreeNode* root, vector<int>& res) {
    if (!root) return res;
    postorder(root->left, res);
    postorder(root->right, res);
    res.push_back(root->val);
    return res;
}

非递归遍历算法

采用模拟函数栈的方式,递归改非递归的思路:

  1. 栈是后入先出,所以右子节点先于左子结点入栈;
  2. 标记位记录是否已访问过,用于判断是否到达数据处理阶段/返回阶段;

可以改进的地方:

  1. 压栈前判空指针,减少出入栈次数;
  2. 前序遍历可以简化,无需标记位,因为新栈顶元素每次入栈后都是立即出栈;

前序遍历

void preorder(TreeNode *root, vector<int>& res)
{
    if (root == nullptr) return;
    stack< pair<TreeNode*, bool> > stk;
    stk.emplace(root, false);
    while(!stk.empty()) {
        auto [p, visited] = stk.top();
        stk.pop();
        if(visited) {
            res.push_back(p->val);
        } else {
            stk.emplace(p->right, false);
            stk.emplace(p->left, false);
            stk.emplace(p, true);
        }
    }
}

中序遍历

void inorder(TreeNode *root, vector<int>& res)
{
    if (root == nullptr) return;
    stack< pair<TreeNode*, bool> > stk;
    stk.emplace(root, false);
    while(!stk.empty()) {
        auto [p, visited] = stk.top();
        stk.pop();
        if(visited) {
            res.push_back(p->val);
        } else {
            stk.emplace(p->right, false);
            stk.emplace(p, true);
            stk.emplace(p->left, false);
        }
    }
}

后序遍历

void postorder(TreeNode *root, vector<int>& res)
{
    if (root == nullptr) return;
    stack< pair<TreeNode*, bool> > stk;
    stk.emplace(root, false);
    while(!stk.empty()) {
        auto [p, visited] = stk.top();
        stk.pop();
        if(visited) {
            res.push_back(p->val);
        } else {
            stk.emplace(p, true);
            stk.emplace(p->right, false);
            stk.emplace(p->left, false);
        }
    }
}
posted @ 2021-02-21 10:51  与MPI做斗争  阅读(191)  评论(0编辑  收藏  举报