二叉树是常见的数据结构,二叉树相关的算法题目也是非常常见的。下面总结以下二叉树的前序/中序/后序遍历方法,分别用递归(O(n) Space),迭代(O(n) Space),Morris(O(1) Space)方法实现。

二叉树遍历的时间复杂度都是O(n),不同方法的区别主要是在空间复杂度上。


Recursive Traversal

递归是一种非常直观的方法,也是最容易实现的方法。递归的方法的空间复杂度为O(n)。
节点的定义如下:

// Definition for a binary tree node.
struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
}

Preorder Traversal

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

Inorder Traversal

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

Postorder Traversal

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

Iterative Traversal

迭代方法需要使用stack来保存遍历路径上待遍历的节点,从根节点到叶节点,最多保存n/2个节点。空间复杂度为O(n)。

Preorder Traversal

void preorderTraversal(TreeNode* root, vector<int>& nums) {vector<int> nums;vector<int> nums;stack<TreeNode* > st; // pointers in stack are validwhile (root || !st.empty()) {if (!root) {root = st.top();st.pop();}            nums.push_back(root->val);// if valid right child, push into stack if (root->right) st.push(root->right);// go to the left childroot = root->left;}       return nums;
}

Inorder Traversal

vector<int> inorderTraversal(TreeNode* root) {vector<int> nums;stack<TreeNode* > st; // pointers in stack are validwhile (root || !st.empty()) {if (root) {// push root into stack, then go leftst.push(root);root = root->left;} else { // for nodes in stack, only visit its rightroot = st.top();st.pop();nums.push_back(root->val);root = root->right;}}return nums;
}

Postorder Traversal

后序遍历可以看作是和前序遍历是左右对称的,从根节点开始,先遍历右子树,再遍历左子树,只不过为了得到后序遍历的输出,我们需要遍历结果逆序输出。可以比较前序遍历的代码,逻辑完全是一样的,就是左右子树访问顺序交换了,完全是对称的。

vector<int> postorderTraversal(TreeNode* root) {vector<int> nums;stack<TreeNode* > stnode;while (root || !stnode.empty()) {if (!root) {root = stnode.top();stnode.pop();}nums.push_back(root->val);if (root->left) stnode.push(root->left);root = root->right;}return vector<int>(nums.rbegin(), nums.rend())
} 

Morris Traversal

Morris遍历方法不需要栈来保存待访问的节点,而是通过利用节点本身的指针来保存待访问节点的指针,并在访问过程中恢复节点。实现了O(1)空间复杂度。

Preorder Traversal

图片摘自Reference4Reference^4

vector<int> preorderTraversal(TreeNode* root) {// morris traversalvector<int> nums;TreeNode* cur = nullptr;while (root) {if (root->left) {cur = root->left;// find the predecessor of root nodewhile (cur->right && cur->right != root) {cur = cur->right;}// has visited this root nodeif (cur->right == root) {cur->right = nullptr;root = root->right;} else {nums.push_back(root->val);cur->right = root;root = root->left;}} else {nums.push_back(root->val);   root = root->right;}}return nums;
} 

Inorder Traversal

中序和前序代码基本一样,唯一不同的在输出节点值的顺序不同。

图片摘自Reference4Reference^4

vector<int> inorderTraversal(TreeNode* root) {vector<int> inorderTraversal(TreeNode* root) {vector<int> nums;TreeNode* cur = nullptr;while (root) {if (root->left) {cur = root->left;while (cur->right && cur->right != root) {cur = cur->right;}if (cur->right == root) {nums.push_back(root->val);cur->right = nullptr;root = root->right;} else {cur->right = root;root = root->left;}               } else {nums.push_back(root->val);root = root->right;}}return nums;}
} 

Postorder Traversal

之前我们在讲迭代方法时,说过了后序遍历其实可以看作是和前序遍历左右对称的,此处,我们同样可以利用这个性质,基于前序遍历的算法,可以很快得到后序遍历的结果。我们只需要将前序遍历中所有的左孩子和右孩子进行交换就可以了。

图片摘自Reference4Reference^4


vector<int> postorderTraversal(TreeNode* root) {vector<int> nums;TreeNode* cur = nullptr;while (root) {if (root->right) {cur = root->right;while (cur->left && cur->left != root) {cur = cur->left;}if (cur->left == root) {cur->left = nullptr;root = root->left;} else {nums.push_back(root->val);cur->left = root;root = root->right;}} else {nums.push_back(root->val);root = root->left;}}return vector<int>(nums.rbegin(), nums.rend());
}

Reference

1. https://leetcode.com/problems/binary-tree-preorder-traversal/description/
2. https://leetcode.com/problems/binary-tree-inorder-traversal/description/
3. https://leetcode.com/problems/binary-tree-postorder-traversal/description/
4. http://www.cnblogs.com/AnnieKim/archive/2013/06/15/MorrisTraversal.html


二叉树的遍历-Recursive/Iterative/Morris相关推荐

  1. 二叉树的遍历(递归,非递归,Morris)

    二叉树的遍历 目录 递归遍历 非递归遍历 Morris遍历 1. 递归遍历 递归版遍历只要当前节点不为null,就可以三次回到当前节点. public static void preOrderRecu ...

  2. 二叉树的遍历(递归、栈、morris莫里斯算法)三种方法

    二叉树的前序遍历 递归 class TreeNode{TreeNode left;TreeNode right;int val;public TreeNode(){}public TreeNode(i ...

  3. 遍历二叉树的神级方法-Morris遍历【建议收藏】

    在前面,我们简单提及过二叉树的遍历方式,有递归和非递归两个版本的遍历.仔细想一想,不管是递归的,还是非递归的遍历,两种版本的遍历都是需要耗费大量的.额外的空间.比如当我们二叉树的高度有100层,那么递 ...

  4. 重拾算法(3)——用458329个测试用例全面测试二叉树和线索二叉树的遍历算法

    重拾算法(3)--用458329个测试用例全面测试二叉树和线索二叉树的遍历算法 在"上一篇"和"上上一篇"中,我给出了二叉树和线索二叉树的遍历算法.给出算法容易 ...

  5. 二叉树的遍历及解题思路

    文章目录 二叉树的遍历 一.深度优先遍历 1. 先序遍历 (1) 递归形式 (2) 非递归形式 2. 中序遍历 (1) 递归形式 (2) 非递归形式 3. 后序遍历 (1) 递归形式 (2) 非递归形 ...

  6. c语言二叉树的遍历菜单系统,C语言二叉树的三种遍历方式的实现及原理

    C语言二叉树的三种遍历方式的实现及原理 发布时间:2020-10-03 19:43:57 来源:脚本之家 阅读:63 作者:看雪. 二叉树遍历分为三种:前序.中序.后序,其中序遍历最为重要.为啥叫这个 ...

  7. html二叉树遍历,二叉树的遍历算法

    二叉树的遍历算法 概述 二叉树作为一个基础的数据结构,遍历算法作为一个基础的算法,两者结合当然是经典的组合了.很多题目都会有 ta 的身影,有直接问二叉树的遍历的,有间接问的.比如要你找到树中满足条件 ...

  8. 二叉树的遍历(递归与非递归)

    class Node: # 定义树节点def __init__(self, value, left=None, right=None): # 节点的值及左子树.右子树self.value = valu ...

  9. 刷题:二叉树的遍历方式及根据遍历结果还原二叉树

    二叉树的遍历方式及根据遍历结果还原二叉树 1. 二叉树的遍历方式 2. 根据遍历结果还原二叉树 2.1 已知先序遍历和中序遍历还原二叉树 2.2 已知后序遍历和中序遍历还原二叉树 实验代码: 1. 二 ...

最新文章

  1. ligerui tree mysql_LigerUi中下拉框一级树tree数据库读取代码示例!
  2. SwitchyOmega 配置
  3. 禁止Dockpanel拖动
  4. 【HDU - 2398 】Savings Account (水题模拟)
  5. 单边指数信号的特点_今日股市分析:上证指数若能守住3400,蓄力反弹就有戏...
  6. 如何使用 volatile, synchronized, final 进行线程间通信
  7. 自己动手Centos7搭建wordpress网站步骤(LNMP+wordpress)
  8. MYSQL正在使用select发现现场记录方法,包括一个逗号分隔的字符串
  9. abaqus算出来的转角单位是什么_ABAQUS中的单位制是如何规定的;
  10. 2019新买电脑必备软件
  11. PowerDesigner画UML图
  12. 迷你迅雷+SqlServer2008r2下载
  13. 【PhotoShop基础A篇】磨皮/图层/液化
  14. js中函数传参的问题
  15. 宠物商店——三层架构
  16. 22条创业军规(读书)
  17. Java实现 kiosk模式,Android中的Kiosk模式
  18. 台式计算机无线网经常掉线,电脑无线网老是掉线怎么办?教你解决掉线问题
  19. 在线上也能进行商标注册
  20. 2019 NIPS | Variational graph recurrent neural network

热门文章

  1. 一年级男生上课不专心,说了很多次都不改!
  2. python音频颤音算法_数字音效算法的研究与实现
  3. 日程管理APP测试用例
  4. 2022年中国人工智能芯片行业发展现状及发展趋势分析:芯片需求持续增长,发展空间大[图]
  5. 用C++开发windowsNT服务
  6. 计算机视觉相关论文,有关计算机视觉的课程论文
  7. Π和根据阈值和关系式求圆周率
  8. Python中turtle库(五)——递归
  9. 软件测试培训费用多少?
  10. 认识与应用声卡的“S/PDIF”接口