BM23、24、25 二叉树的前序、中序、后续遍历

本文介绍了如何使用深度优先搜索(DFS)的递归方法实现二叉树的后序遍历。在给定的代码示例中,展示了前序、中序和后序遍历的不同顺序,并提供了后序遍历的具体实现,其时间复杂度为O(n)。

 二叉树的后序遍历_牛客题霸_牛客网 (nowcoder.com)

前序、后续、中序遍历原理相似

利用dfs算法 递归去做

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型vector
     */
    
    void dfs(vector<int> &res, TreeNode* root){
        if(root == nullptr) return ;

        /* 前序
        res.push_back(root->val);
        dfs(res,root->left);
        dfs(res,root->right);
        */

        /* 中序
        dfs(res,root->left);
        res.push_back(root->val);
        dfs(res,root->right);
        */
        
        /* 后序
        dfs(res,root->left);
        dfs(res,root->right);
        res.push_back(root->val);
        */
        
    }
    vector<int> preorderTraversal(TreeNode* root) {
        // write code here
        vector<int> res;
        dfs(res, root);
        return res;
    }
};

需要遍历所有节点,时间复杂度On 

<think>首先,用户的问题是:“我想查找二叉树前序、中、后遍历结果相同的处理方法。请问二叉树前序遍历结果相同的处理方法?” 我需要基于用户提供的引用内容来回答这个问题。用户的引用包括: - 引用[1]:讨论了如何从前序和中遍历求后遍历,或者从中和后遍历前序遍历。 - 引用[2]:定义了前序、中、后和层次遍历的顺。 - 引用[3]:展示了用代码从前序和中构建二叉树,或从中和后构建二叉树。 - 引用[4]:展示了二叉树遍历的JavaScript代码示例。 用户的问题核心是:当前序、中和后遍历结果相同时,如何处理这种情况。 回想二叉树遍历定义: - 前序遍历:根节点 -> 左子树 -> 右子树 - 中遍历:左子树 -> 根节点 -> 右子树 - 后遍历:左子树 -> 右子树 -> 根节点 用户想知道当这三种遍历列相同时的处理方法。 在正常情况下,二叉树前序、中和后遍历列是不同的,因为它们访问节点的顺不同。只有当二叉树的结构特殊时,这些列才可能相同。 考虑一个二叉树的结构: - 如果二叉树是空的,那么所有遍历列都是空的,所以相同。但这可能不是用户的意思。 - 更实际的是,如果二叉树只有一个节点(根节点),那么前序、中和后遍历都只有一个节点,所以列相同。 - 另一个例子:如果二叉树的所有节点都只有右子树,没有左子树(即一条向右的链)。 - 例如:根 -> 右孩子 -> 右孙子 -> ... - 前序遍历:根、右孩子、右孙子...(顺是先根,然后右子树) - 中遍历:根、右孩子、右孙子...(因为左子树为空,所以根后立即右子树) - 后遍历:右孙子、右孩子、根...(先访问右子树,最后根) 在这种情况下,列是不同的。中前序在某些结构中相似,但一般来说不同。 仔细想想: - 前序:根、左、右 - 中:左、根、右 - 后:左、右、根 要使所有三种列相同,必须满足:根节点访问时,左子树和右子树都不存在,或者整个树的结构简化。 事实上,只有当二叉树没有分支时,即每个节点最多有一个孩子时,列可能在某些情况下匹配。 具体来说: 1. 空树:所有遍历列为空。 2. 单节点树:所有列相同,只有一个元素。 3. 对于更复杂的树:假设每个节点只有右孩子(或只有左孩子)。 - 只有右孩子的树: - 前序:根、右子树(列是根、右孩子、右孙子...) - 中:左子树为空,所以根、然后右子树(列根、右孩子、右孙子...)——与前序相同。 - 后:右子树、然后根(列右孙子、右孩子、根...)——与前序和中不同。 - 只有左孩子的树: - 前序:根、左子树(根、左孩子、左孙子...) - 中:左子树、根(左孙子、左孩子、根...)——与前序不同。 - 后:左子树、根(左孙子、左孩子、根...)——与中相同,但与前序不同。 所以,在只有右孩子的情况下,前序和中相同,但后不同。在只有左孩子的情况下,中和后相同,但前序不同。 要使所有三种列相同,必须是每个节点没有两个孩子,并且列顺一致。实际上,只有一个节点时相同。 另一个可能性:如果二叉树是完全不平衡的,但列相同的情况很少见。 我回忆起:对于一棵二叉树,当前序和中相同,或者中和后相同时,树的结构有特定形式。 但用户问的是前序、中和后所有三种相同时的处理方法。 在极端情况下: - 如果树为空,列相同(空)。 - 如果树只有一个节点,列相同。 - 如果树有多个节点,但所有节点都只有右孩子(斜树),那么: - 前序:A,B,C(如果A是根,B是右孩子,C是右孙子) - 中:A,B,C(因为左为空) - 后:C,B,A 这里前序和中相同,但后不同。 类似地,对于只有左孩子的斜树: - 前序:A,B,C(A根,B左孩子,C左孙子) - 中:C,B,A - 后:C,B,A 所以前序不同,中和后相同。 要使所有三种相同,必须没有子树,或者列中节点顺相同。但基于遍历,只有当树只有根节点时,列才完全相同。 考虑一个更小的例子:根和一个左孩子。 - 节点:A(根),B(左孩子) - 前序:A,B - 中:B,A - 后:B,A 列不同。 类似地,根和一个右孩子: - 前序:A,B - 中:A,B - 后:B,A 列不同(前序和中相同,但后不同)。 因此,二叉树的节点数大于1时,前序、中和后列不可能完全相同,因为它们的遍历强制不同的列顺(根在开始、中间或结束)。 结论:对于二叉树前序、中和后遍历列只有在树为空或只有一个节点时才相同。 那么,处理方法就是识别这种情况:如果遍历列相同,那么树要么是空的,要么只有一个节点。 在编程中,处理这种情况很简单: - 如果输入列为空,返回空树。 - 如果列只有一个元素,创建一个单节点树返回。 在构建二叉树的上下文中,如用户引用中,给出遍历列求树结构时,如果列相同,则树是退化或简单的。 在用户的引用[1]和[3]中,展示了如何从前序和中或从中和后遍历列构建二叉树。 如果列相同,意味着树只有一个节点或空。 所以,在算法中,可以添加检查: - 如果列长度小于等于1,直接返回。 例如,在引用[3]的代码中: ```cpp TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) { if (preorder.empty()) { // 空节点 return nullptr; } // 如果列长度为1,创建一个节点返回 // 代码中,preorder[0]是根,然后分割... // 但代码没有显式处理长度1,但递归会处理,因为当左子树大小为0时,pre1和in1为空,递归返回nullptr。 } ``` 在递归中,当列长度为1时,它会正确处理:创建节点,左子树和右子树递归调用时,因为left_size=0,所以pre1和in1为空,buildTree返回nullptr,类似pre2和in2如果右子树为空。 所以在标准算法中,列相同的情况自然被处理,因为列长度为0或1时,树为空或单节点。 用户的问题是“处理方法”,所以我应该解释当列相同时,树的结构简单,并建议在算法中添加检查或理解其含义。 另外,用户可能误解了,或者有特殊情况。 在引用中,没有直接提到列相同的情况,所以我基于一般知识回答。 回答结构: 1. 解释当二叉树前序、中和后遍历列相同时,这意味着树只有根节点或为空。 2. 在构建二叉树算法中,这种情况已经隐含处理,因为递归基础情况处理空列或单元素列。 3. 给出简单示例或代码片段。 4. 生成相关问题。 最后,添加引用标识。 系统指令要求:使用中文回答;生成相关问题;添加引用标识。 引用来源是用户提供的[^1], [^2], [^3], [^4]。 在我的回答中,需要自然地添加引用,例如当提到遍历定义时引用[^2],当提到构建算法时引用[^1]或[^3]。 生成相关问题。 完整回答: </think>### 二叉树前序、中、后遍历结果相同的处理方法 在二叉树中,前序遍历(根节点 -> 左子树 -> 右子树)、中遍历(左子树 -> 根节点 -> 右子树)和后遍历(左子树 -> 右子树 -> 根节点)的列通常不同,因为它们访问节点的顺存在本质差异[^2]。只有当二叉树的结构极其特殊时,这三种遍历列才可能完全相同。以下是针对这种情况的处理方法: 1. **列相同时的二叉树结构分析**: - **空树情况**:如果二叉树为空(节点数为0),所有遍历列均为空列([]),因此相同。处理方法:直接返回空树(`nullptr` 或类似表示)。 - **单节点树情况**:如果二叉树只有一个根节点(无左子树和右子树),所有遍历列均为单元素列(例如 `[A]`),因此相同。处理方法:创建单节点树返回。 - **多节点树情况**:对于节点数 ≥ 2 的二叉树前序、中和后列不可能完全相同。因为: - 前序遍历根节点在列开头。 - 中遍历根节点在列中间。 - 后遍历根节点在列末尾。 例如,对于有两节点的树(根和一个左孩子),前序为 `[A,B]`,中为 `[B,A]`,后为 `[B,A]`——列不同。类似地,斜树(所有节点只有右孩子或左孩子)也无法满足所有列相同[^1][^2]。 2. **编程实现中的处理方法**: - 在构建二叉树算法中(如从前序和中列重建),列相同的情况通常已隐含处理。标准递归算法会自然处理空列或单元素列作为基础情况。以下是基于引用[^1]和[^3]的优化处理: - **检查列长度**:在递归函数开头,添加显式检查,避免不必要的递归。 - **示例代码(Java风格,基于引用[^1])**: ```java public TreeNode buildTree(int[] preorder, int[] inorder) { if (preorder.length == 0) { // 空树情况 return null; } if (preorder.length == 1) { // 单节点树情况 return new TreeNode(preorder[0]); } // 如果列相同(长度相同且元素全等),直接创建单节点树 boolean allSame = true; for (int i = 0; i < preorder.length; i++) { if (preorder[i] != inorder[i]) { // 假设postorder相同,但通常需额外检查 allSame = false; break; } } if (allSame) { return new TreeNode(preorder[0]); // 列相同,返回单节点树 } // 否则,正常递归构建(基于前序和中) int rootVal = preorder[0]; int rootIndex = 0; while (inorder[rootIndex] != rootVal) { rootIndex++; } // 分割左子树和右子树列 int[] leftPreorder = Arrays.copyOfRange(preorder, 1, 1 + rootIndex); int[] leftInorder = Arrays.copyOfRange(inorder, 0, rootIndex); int[] rightPreorder = Arrays.copyOfRange(preorder, 1 + rootIndex, preorder.length); int[] rightInorder = Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length); TreeNode left = buildTree(leftPreorder, leftInorder); TreeNode right = buildTree(rightPreorder, rightInorder); return new TreeNode(rootVal, left, right); } ``` - **关键点**: - 显式处理列长度 ≤1 的情况,提高效率。 - 如果输入列长度相同且元素全等,直接返回单节点树(因为列相同隐含树结构简单)。 - 正常列时,使用递归分割(前序根确定根值,中定位根索引)[^1][^3]。 3. **实际应用注意事项**: - **列有效性验证**:在输入列时,先验证长度是否一致。如果长度不一致,说明列无效(遍历列长度应相同)。引用[^2]强调遍历定义的一致性。 - **性能优化**:对于列相同的情况,跳过递归直接返回,减少时间复杂度(从 $O(n^2)$ 优化到 $O(1)$)。 - **边界场景**:在空树或单节点树中,列相同是正常行为,无需特殊处理。但如果输入列相同且长度 >1,应检查数据错误(例如列生成 bug)。 - **JavaScript 示例**:引用[^4]展示了遍历代码,类似地,可在遍历函数中添加前置检查: ```javascript function buildTree(preorder, inorder) { if (preorder.length === 0) return null; if (preorder.length === 1) return new Node(preorder[0]); if (JSON.stringify(preorder) === JSON.stringify(inorder)) { return new Node(preorder[0]); // 列相同,返回单节点 } // ...正常递归构建 } ``` 总结:二叉树前序、中和后遍历列相同仅当树为空或单节点时出现。处理方法是通过显式检查列长度和内容,直接返回对应树结构,避免冗余计算。这适用于二叉树构建算法(如 LeetCode 相关问题),并确保鲁棒性[^1][^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值