首页 > 其他分享 >Binary Tree Preorder Traversal

Binary Tree Preorder Traversal

时间:2023-08-12 22:34:11浏览次数:54  
标签:Binary right TreeNode val Tree Traversal result root left

Source

Given a binary tree, return the preorder traversal of its nodes' values.

Note
Given binary tree {1,#,2,3},

   1
    \
     2
    /
   3

return [1,2,3].

Example
Challenge
Can you do it without recursion?

题解1 - 递归

递归版很好理解,首先判断当前节点(根节点)是否为 null,是则返回空 vector,否则先返回当前节点的值,然后对当前节点的左节点递归,最后对当前节点的右节点递归。递归时对返回结果的处理方式不同可进一步细分为遍历和分治两种方法。

C++ - Divide and Conquer

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: The root of binary tree.
     * @return: Preorder in vector which contains node values.
     */
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        if (root != NULL) {
            // Divide
            vector<int> left = preorderTraversal(root->left);
            vector<int> right = preorderTraversal(root->right);
            // Merge
            result.push_back(root->val);
            result.insert(result.end(), left.begin(), left.end());
            result.insert(result.end(), right.begin(), right.end());
        }

        return result;
    }
};

C++ - Traversal

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: The root of binary tree.
     * @return: Preorder in vector which contains node values.
     */
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        traverse(root, result);

        return result;
    }

private:
    void traverse(TreeNode *root, vector<int> &ret) {
        if (root != NULL) {
            ret.push_back(root->val);
            traverse(root->left, ret);
            traverse(root->right, ret);
        }
    }
};

Java - Divide and Conquer

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();
        if (root != null) {
            // Divide
            List<Integer> left = preorderTraversal(root.left);
            List<Integer> right = preorderTraversal(root.right);
            // Merge
            result.add(root.val);
            result.addAll(left);
            result.addAll(right);
        }

        return result;
    }
}

Java - Traversal

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    private List<Integer> result = new ArrayList<Integer>();

    public List<Integer> preorderTraversal(TreeNode root) {
        if (root != null) {
            result.add(root.val);
            preorderTraversal(root.left);
            preorderTraversal(root.right);
        }

        return result;
    }
}

源码分析

使用遍历的方法保存递归返回结果需要使用辅助递归函数traverse,将结果作为参数传入递归函数中,传值时注意应使用vector的引用。另外一个方法则是使用类的私有变量保存最终结果。 分治方法首先分开计算各结果,最后合并到最终结果中。 C++ 中由于是使用vector, 将新的vector插入另一vector不能再使用push_back, 而应该使用insert。 Java 中使用addAll方法.

复杂度分析

遍历树中节点,时间复杂度 O(n), 遍历的方法未使用额外空间,分治的方法生成了临时变量,最差情况下空间复杂度为 (n).

 

题解2 - 迭代

迭代时需要利用栈来保存遍历到的节点,纸上画图分析后发现应首先进行出栈抛出当前节点,保存当前节点的值,随后将右、左节点分别入栈(注意入栈顺序,先右后左),迭代到其为叶子节点(NULL)为止。

C++

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: The root of binary tree.
     * @return: Preorder in vector which contains node values.
     */
    vector<int> preorderTraversal(TreeNode *root) {
        vector<int> result;
        if (root == NULL) return result;

        stack<TreeNode *> s;
        s.push(root);
        while (!s.empty()) {
            TreeNode *node = s.top();
            s.pop();
            result.push_back(node->val);
            if (node->right != NULL) {
                s.push(node->right);
            }
            if (node->left != NULL) {
                s.push(node->left);
            }
        }

        return result;
    }
};

Java

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<Integer>();

        Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
        if (root != null) stack.push(root);
        while (!stack.isEmpty()) {
            root = stack.pop();
            result.add(root.val);
            if (root.right != null) stack.push(root.right);
            if (root.left != null) stack.push(root.left);
        }

        return result;
    }
}

源码分析

  1. 对root进行异常处理
  2. 将root压入栈
  3. 循环终止条件为栈s为空,所有元素均已处理完
  4. 访问当前栈顶元素(首先取出栈顶元素,随后pop掉栈顶元素)并存入最终结果
  5. 将右、左节点分别压入栈内,以便取元素时为先左后右。
  6. 返回最终结果

其中步骤4,5,6为迭代的核心,对应前序遍历「根左右」。

所以说到底,使用迭代,只不过是另外一种形式的递归。使用递归的思想去理解遍历问题会容易理解许多。

复杂度分析

使用辅助栈,最坏情况下栈空间与节点数相等,其空间复杂度为 O(n), 对每个节点遍历一次,时间复杂度为 O(n).      

标签:Binary,right,TreeNode,val,Tree,Traversal,result,root,left
From: https://www.cnblogs.com/lyc94620/p/17625689.html

相关文章

  • Subtree 题解
    Subtree题目大意给定一颗树,你可以选出一些节点,你需要对于每个点求出在强制选这个点的情况下所有选择的点联通的方案数,对给定模数取模。思路分析对于这种求树上每一个点方案数的题目,首先考虑换根DP。强制嵌定树根为\(1\),设\(f_i\)表示在\(i\)的子树中选点,\(i\)强制选,所......
  • SourceTree git报错 这是一个无效源路径/URL的
    首先根据网上查询的资料排查账号信息,账号信息正常,git客户端也安装了 解决问题:git支持未打开  未打开的样式类似下面 ......
  • dus on tree学习笔记
    前言dusontree就像其实就像是暴力,但是通过选择正确的顺序,使得暴力变得更加的快速。算法思路查看题目给出一颗n个节点的树,每个节点有一个颜色,询问你没个节点的子树中有多少中颜色。显然,我们知道暴力扫的话是枚举每个点,再暴力去找他的子树,显然在暴力的情况下是\(O(n......
  • Paper Reading: NBDT: Neural-Backed Decision Trees
    目录研究动机文章贡献本文方法推理建立层次结构用WordNet标记决策节点微调和树监督损失实验结果对比实验结果可解释性识别错误的模型预测引导图像分类人更倾向的解释识别有缺陷的数据标签优点和创新点PaperReading是从个人角度进行的一些总结分享,受到个人关注点的侧重和实力......
  • 全局引用ant-design-vue的TreeSelect没有样式
    在全局只按需引用了TreeSelect---vue.use(TreeSelect)没有样式.........需要在babel.config.js里的plugins配置plugins:[["import",{"libraryName":"ant-design-vue",//库名称"libraryDirectory"......
  • el-tree 全部禁用 超简单解决办法
    有这么个需求,要求el-tree有多选框,但是要全部禁用,只展示看 但是el-tree这个属性上没有看到全部禁用的属性,只看到了单个节点禁用,所以有一个麻烦的办法,就是递归禁用所有节点,但是这个方法麻烦耗时,所以看到官方文档有这么个东西 于是我们想办法,把这个Props用上,于是就这样了......
  • elementui el-tree的使用方法
    el-tree一般用于节点下有很多子节点接口返回的数据格式,可以无线子节点deptOptions:[{"id":"1686631142746230785","label":"小王测试部门","children":[{"id&......
  • vue+el-tree 通过下拉框选中节点,定位到当前节点,并高亮
    此处为下拉选择器:<el-selectref="searchSelect"v-model="filter"filterableremotesize="mini"clearableplaceholder="请输入关键词":remo......
  • Paper Reading: Multitree Genetic Programming With New Operators for Transfer Lea
    目录研究动机文章贡献本文方法从源域中提取知识基于MTGP的迁移学习转换域的特征、实例权值数据插值MTGP适应度函数遗传算子实验结果数据集实验设置同构情况下的SR异构情况下的SR存在缺失值的真实数据集的SR训练时间学习到的转换表达式遗传算子比较消融实验优点和创新点Pape......
  • WPF自定义TreeView滚动条样式
     根据客户需求,要在TreeView目录树上显示10万+个节点,但是目录树显示10万加节点后,整个页面操作起来非常卡,所以给目录树增加了虚拟化设置。但是虚拟化设置一直没生效,后来经过排查发现是使用的自定义滚动条导致了虚拟化设置没有生效,后来自己写了一个滚动条样式,问题解决了。目录树虚......