zoukankan      html  css  js  c++  java
  • 二叉树深度优先遍历总结

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

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

    太长不看版(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);
            }
        }
    }
    
  • 相关阅读:
    python daemon install
    添加 sudoer centos
    CentOS 5安装openssh
    java使用sh或是jsvc来做daemon应该是主流
    Maven JAR Plugin
    The Java™ Tutorials offical学习的好资料哦
    linux下lrzsz安装,SecureCRT上传下载文件工具 寒枫欣叶
    ssh on centos5
    CentOS Linux Install Core Development Tools Automake, Gcc (C/C++), Perl, Python & Debuggers
    Setting an Application's Entry Point
  • 原文地址:https://www.cnblogs.com/zhcpku/p/14424453.html
Copyright © 2011-2022 走看看