当前位置: 首页 > news >正文

二叉树的三种遍历方法

一、二叉树遍历基础概念

二叉树的遍历是指按某种规则访问树中所有节点,且每个节点仅访问一次。核心的三种遍历方式基于节点访问顺序划分:

  • 前序遍历(Pre-order):根节点 → 左子树 → 右子树        “根左右”
  • 中序遍历(In-order):左子树 → 根节点 → 右子树          “左根右”
  • 后序遍历(Post-order):左子树 → 右子树 → 根节点       “左右根”

以下实现基于二叉树节点的标准定义:

struct TreeNode {int val;TreeNode *left;  // 左子节点TreeNode *right; // 右子节点TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

二、递归实现(简洁直观)

递归是二叉树遍历最自然的实现方式,利用函数栈实现节点访问顺序控制。

2.1 前序遍历(递归)

#include <vector>
using namespace std;// 前序遍历:根 → 左 → 右
void preorderRecursive(TreeNode* root, vector<int>& result) {if (root == nullptr) return; // 递归终止条件:空节点result.push_back(root->val); // 访问根节点preorderRecursive(root->left, result);  // 遍历左子树preorderRecursive(root->right, result); // 遍历右子树
}// 对外接口
vector<int> preorderTraversal(TreeNode* root) {vector<int> result;preorderRecursive(root, result);return result;
}

2.2 中序遍历(递归)

// 中序遍历:左 → 根 → 右
void inorderRecursive(TreeNode* root, vector<int>& result) {if (root == nullptr) return;inorderRecursive(root->left, result);  // 遍历左子树result.push_back(root->val); // 访问根节点inorderRecursive(root->right, result); // 遍历右子树
}// 对外接口
vector<int> inorderTraversal(TreeNode* root) {vector<int> result;inorderRecursive(root, result);return result;
}

2.3 后序遍历(递归)

// 后序遍历:左 → 右 → 根
void postorderRecursive(TreeNode* root, vector<int>& result) {if (root == nullptr) return;postorderRecursive(root->left, result);  // 遍历左子树postorderRecursive(root->right, result); // 遍历右子树result.push_back(root->val); // 访问根节点
}// 对外接口
vector<int> postorderTraversal(TreeNode* root) {vector<int> result;postorderRecursive(root, result);return result;
}

递归优势:代码简洁,逻辑清晰;缺点:深度过大时可能栈溢出,不适合极端大规模树。

三、迭代实现(手动控制栈)

迭代方式通过显式栈模拟递归过程,避免递归栈溢出风险,更适合工程实践。

3.1 前序遍历(迭代)

核心思路:根节点先入栈,出栈时访问,再依次入栈右子树、左子树(利用栈的 LIFO 特性)。

vector<int> preorderTraversal(TreeNode* root) {vector<int> result;if (root == nullptr) return result;stack<TreeNode*> st;st.push(root); // 根节点先入栈while (!st.empty()) {TreeNode* node = st.top();st.pop();result.push_back(node->val); // 访问根节点// 右子树先入栈(后访问),左子树后入栈(先访问)if (node->right != nullptr) st.push(node->right);if (node->left != nullptr) st.push(node->left);}return result;
}

3.2 中序遍历(迭代)

核心思路:左子树一路入栈,触底后出栈访问,再转向右子树重复。

vector<int> inorderTraversal(TreeNode* root) {vector<int> result;if (root == nullptr) return result;stack<TreeNode*> st;TreeNode* cur = root;while (cur != nullptr || !st.empty()) {// 左子树全部入栈while (cur != nullptr) {st.push(cur);cur = cur->left;}// 出栈访问根节点cur = st.top();st.pop();result.push_back(cur->val);// 转向右子树cur = cur->right;}return result;
}

3.3 后序遍历(迭代)

核心思路:前序遍历变种(根→右→左),最后反转结果得到左→右→根。

vector<int> postorderTraversal(TreeNode* root) {vector<int> result;if (root == nullptr) return result;stack<TreeNode*> st;st.push(root);while (!st.empty()) {TreeNode* node = st.top();st.pop();result.push_back(node->val); // 先按根→右→左顺序收集// 左子树先入栈(后访问),右子树后入栈(先访问)if (node->left != nullptr) st.push(node->left);if (node->right != nullptr) st.push(node->right);}reverse(result.begin(), result.end()); // 反转得到后序遍历return result;
}

迭代优势:无栈溢出风险,可控性强;缺点:逻辑稍复杂,需手动控制节点入栈顺序。

四、遍历验证与示例

4.1 测试用例构建

以如下二叉树为例,验证三种遍历结果:

      1\2/3

构建代码:

TreeNode* buildTestTree() {TreeNode* root = new TreeNode(1);root->right = new TreeNode(2);root->right->left = new TreeNode(3);return root;
}

4.2 预期输出

  • 前序遍历:[1, 2, 3]
  • 中序遍历:[1, 3, 2]
  • 后序遍历:[3, 2, 1]

五、三种遍历对比与应用场景

遍历方式访问顺序递归复杂度迭代复杂度典型应用场景
前序遍历根→左→右O (n) 时间 / O (h) 空间O (n) 时间 / O (h) 空间复制二叉树、前缀表达式求值
中序遍历左→根→右O (n) 时间 / O (h) 空间O (n) 时间 / O (h) 空间二叉搜索树排序(左 < 根 < 右)
后序遍历左→右→根O (n) 时间 / O (h) 空间O (n) 时间 / O (h) 空间计算树深度、释放节点内存

(注:n 为节点数,h 为树的高度,平衡树 h=logn,极端链状树 h=n)

六、代码封装与扩展

实际开发中可封装为工具类,支持多种遍历方式切换:

class BinaryTreeTraversal {
public:enum TraversalType { PREORDER, INORDER, POSTORDER };vector<int> traverse(TreeNode* root, TraversalType type) {switch (type) {case PREORDER: return preorder(root);case INORDER: return inorder(root);case POSTORDER: return postorder(root);default: return {};}}private:// 此处省略前序、中序、后序的迭代实现(复用前文代码)vector<int> preorder(TreeNode* root) { /* ... */ }vector<int> inorder(TreeNode* root) { /* ... */ }vector<int> postorder(TreeNode* root) { /* ... */ }
};

扩展建议

  • 增加层序遍历(广度优先)支持;
  • 实现 Morris 遍历(O (1) 空间复杂度,无栈);
  • 支持自定义节点访问函数(如打印、计算等)。

通过掌握二叉树的三种核心遍历方式,可奠定树结构算法的基础,后续复杂树问题(如路径求和、子树判断)均需基于遍历逻辑扩展。实际开发中根据场景选择递归(简单场景)或迭代(高性能需求)实现。

http://www.dtcms.com/a/334409.html

相关文章:

  • List容器:特性与操作使用指南
  • VS Code配置MinGW64编译GLPK(GNU Linear Programming Kit)开源库
  • 实现Android图片手势缩放功能的完整自定义View方案,结合了多种手势交互功能
  • 纸板制造制胶工艺学习记录4
  • Redis集群设计实战:从90%缓存命中率看高并发系统优化
  • Windows常见文件夹cache的作用还有其他缓存类型文件夹的作用
  • backward怎么计算的是torch.tensor(2.0, requires_grad=True)变量的梯度
  • 【论文阅读】Multimodal Graph Contrastive Learning for Multimedia-based Recommendation
  • Linux 下 安装 matlab 2025A
  • 机器学习——CountVectorizer将文本集合转换为 基于词频的特征矩阵
  • 软件的终极:为70亿人编写70亿个不同的软件
  • C++面试题及详细答案100道( 31-40 )
  • SysTick寄存器(嘀嗒定时器实现延时)
  • cPanel Python 应用部署流程
  • 记录一下第一次patch kernel的经历
  • CSV 生成 Gantt 甘特图
  • 2^{-53} 单位舍入误差、机器精度、舍入的最大相对误差界限
  • 【QGIS数据篇】QGIS 3.40 栅格计算器经典实用公式全集
  • 高并发场景下如何避免重复支付
  • 17.3 全选购物车
  • 双椒派E2000D开发板LED驱动开发实战指南
  • 线程回收与线程间通信
  • [Python 基础课程]抽象类
  • 强化学习入门教程(附学习文档)
  • (第十七期)HTML图像标签详解:从入门到精通
  • 创新词汇表设计:UniVoc - 中英文混合处理的新方案
  • 安卓11 12系统修改定制化_____列举与安卓 9、10 系统在定制化方面的差异与权限不同
  • 数学建模Topsis法笔记
  • 非功能性需求设计:可解释性、鲁棒性、隐私合规
  • 【数据结构初阶】--排序(五):计数排序,排序算法复杂度对比和稳定性分析