二叉树的遍历-Recursive/Iterative/Morris
二叉树是常见的数据结构,二叉树相关的算法题目也是非常常见的。下面总结以下二叉树的前序/中序/后序遍历方法,分别用递归(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相关推荐
- 二叉树的遍历(递归,非递归,Morris)
二叉树的遍历 目录 递归遍历 非递归遍历 Morris遍历 1. 递归遍历 递归版遍历只要当前节点不为null,就可以三次回到当前节点. public static void preOrderRecu ...
- 二叉树的遍历(递归、栈、morris莫里斯算法)三种方法
二叉树的前序遍历 递归 class TreeNode{TreeNode left;TreeNode right;int val;public TreeNode(){}public TreeNode(i ...
- 遍历二叉树的神级方法-Morris遍历【建议收藏】
在前面,我们简单提及过二叉树的遍历方式,有递归和非递归两个版本的遍历.仔细想一想,不管是递归的,还是非递归的遍历,两种版本的遍历都是需要耗费大量的.额外的空间.比如当我们二叉树的高度有100层,那么递 ...
- 重拾算法(3)——用458329个测试用例全面测试二叉树和线索二叉树的遍历算法
重拾算法(3)--用458329个测试用例全面测试二叉树和线索二叉树的遍历算法 在"上一篇"和"上上一篇"中,我给出了二叉树和线索二叉树的遍历算法.给出算法容易 ...
- 二叉树的遍历及解题思路
文章目录 二叉树的遍历 一.深度优先遍历 1. 先序遍历 (1) 递归形式 (2) 非递归形式 2. 中序遍历 (1) 递归形式 (2) 非递归形式 3. 后序遍历 (1) 递归形式 (2) 非递归形 ...
- c语言二叉树的遍历菜单系统,C语言二叉树的三种遍历方式的实现及原理
C语言二叉树的三种遍历方式的实现及原理 发布时间:2020-10-03 19:43:57 来源:脚本之家 阅读:63 作者:看雪. 二叉树遍历分为三种:前序.中序.后序,其中序遍历最为重要.为啥叫这个 ...
- html二叉树遍历,二叉树的遍历算法
二叉树的遍历算法 概述 二叉树作为一个基础的数据结构,遍历算法作为一个基础的算法,两者结合当然是经典的组合了.很多题目都会有 ta 的身影,有直接问二叉树的遍历的,有间接问的.比如要你找到树中满足条件 ...
- 二叉树的遍历(递归与非递归)
class Node: # 定义树节点def __init__(self, value, left=None, right=None): # 节点的值及左子树.右子树self.value = valu ...
- 刷题:二叉树的遍历方式及根据遍历结果还原二叉树
二叉树的遍历方式及根据遍历结果还原二叉树 1. 二叉树的遍历方式 2. 根据遍历结果还原二叉树 2.1 已知先序遍历和中序遍历还原二叉树 2.2 已知后序遍历和中序遍历还原二叉树 实验代码: 1. 二 ...
最新文章
- ligerui tree mysql_LigerUi中下拉框一级树tree数据库读取代码示例!
- SwitchyOmega 配置
- 禁止Dockpanel拖动
- 【HDU - 2398 】Savings Account (水题模拟)
- 单边指数信号的特点_今日股市分析:上证指数若能守住3400,蓄力反弹就有戏...
- 如何使用 volatile, synchronized, final 进行线程间通信
- 自己动手Centos7搭建wordpress网站步骤(LNMP+wordpress)
- MYSQL正在使用select发现现场记录方法,包括一个逗号分隔的字符串
- abaqus算出来的转角单位是什么_ABAQUS中的单位制是如何规定的;
- 2019新买电脑必备软件
- PowerDesigner画UML图
- 迷你迅雷+SqlServer2008r2下载
- 【PhotoShop基础A篇】磨皮/图层/液化
- js中函数传参的问题
- 宠物商店——三层架构
- 22条创业军规(读书)
- Java实现 kiosk模式,Android中的Kiosk模式
- 台式计算机无线网经常掉线,电脑无线网老是掉线怎么办?教你解决掉线问题
- 在线上也能进行商标注册
- 2019 NIPS | Variational graph recurrent neural network