本文主要解决一个问题,如何实现二叉树的前中后序遍历,有两个要求:

1. O(1)空间复杂度,即只能使用常数空间;

2. 二叉树的形状不能被破坏(中间过程允许改变其形状)。

  • 通常,实现二叉树的前序(preorder)、中序(inorder)、后序(postorder)遍历有两个常用的方法:一是递归(recursive),二是使用栈实现的迭代版本(stack+iterative)。这两种方法都是O(n)的空间复杂度(递归本身占用stack空间或者用户自定义的stack),所以不满足要求。
  • Morris Traversal方法可以做到这两点,与前两种方法的不同在于该方法只需要O(1)空间,而且同样可以在O(n)时间内完成。

要使用O(1)空间进行遍历,最大的难点在于,遍历到子节点的时候怎样重新返回到父节点(假设节点中没有指向父节点的p指针),由于不能用栈作为辅助空间。为了解决这个问题,Morris方法用到了线索二叉树(threaded binary tree)的概念。在Morris方法中不需要为每个节点额外分配指针指向其前驱(predecessor)和后继节点(successor),只需要利用叶子节点中的左右空指针指向某种顺序遍历下的前驱节点或后继节点就可以了。

1. 如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。

2. 如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。

a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。当前节点更新为当前节点的左孩子。

b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空(恢复树的形状)。输出当前节点。当前节点更新为当前节点的右孩子。

3. 重复以上1、2直到当前节点为空。

1 struct TreeNode {
2     int val;
3     TreeNode *left;
4     TreeNode *right;
5     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
6 };
void inorderMorrisTraversal(TreeNode *root) {TreeNode *cur = root, *prev = NULL;while (cur != NULL){if (cur->left == NULL)          // 1.{printf("%d ", cur->val);cur = cur->right;}else{// find predecessorprev = cur->left;while (prev->right != NULL && prev->right != cur)prev = prev->right;if (prev->right == NULL)   // 2.a){prev->right = cur;cur = cur->left;}else                       // 2.b){prev->right = NULL;printf("%d ", cur->val);cur = cur->right;}}}
}

Morris Traversal相关推荐

  1. Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)——无非是在传统遍历过程中修改叶子结点加入后继结点信息(传统是stack记录),然后再删除恢复...

    先看看线索二叉树 n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域.利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索 ...

  2. 94. Binary Tree Inorder Traversal

    题目: Given a binary tree, return the inorder traversal of its nodes' values. For example: Given binar ...

  3. 二叉树的遍历-Recursive/Iterative/Morris

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

  4. LeetCode总结 -- 树的遍历篇

    遍历树的数据结构中最常见的操作. 能够说大部分关于树的题目都是环绕遍历进行变体来解决的. 一般来说面试中遇到树的题目是用递归来解决的, 只是假设直接考察遍历. 那么一般递归的解法就过于简单了. 面试官 ...

  5. 前序遍历二叉树代码_二叉树遍历、二叉树深度、代码示例,一点课堂(多岸学院)...

    二叉树的遍历 ★★★★★TreeNode 节点/ Definition for a binary tree node. /public class TreeNode {int val;TreeNode ...

  6. [Alg] 二叉树的非递归遍历

    1. 非递归遍历二叉树算法 (使用stack) 以非递归方式对二叉树进行遍历的算法需要借助一个栈来存放访问过得节点. (1) 前序遍历 从整棵树的根节点开始,对于任意节点V,访问节点V并将节点V入栈, ...

  7. 判断一个树是否为二叉查找树

    一开始还以为这个问题很简单,平时练习的时候也没有多在意,直到...百度二面后一个算法加面以及字节跳动视频面都出现了这个问题,才发现并不是想象中的那么简单. 找了别人的几篇博客看了看,发现别人好像都有过 ...

  8. 石器时代 —— Leetcode刷题日记 (一 百大热题)

    Date: 2019.10.22 - (C++ Version) 文章目录 All Labels: `热题100` L1 两数之和 L2 两数相加 暴力相加 递归 迭代 L3 无重复字符的最长子串 L ...

  9. leetcode 题解 (500-1000题,持续更新,part 2)

    part1(1-500), part3(1000-*) 502. IPO 题意:给定k,w,profits数组和capital数组.k表示最多可完成的任务数.w是初始资本.profits是各个任务的收 ...

  10. 二叉树的前、中、后遍历非递归实现

    https://leetcode-cn.com/tag/tree/ 5/ \3 6 / \ / \ 2 4 7 8 144. 二叉树的前序遍历 https://leetcode-cn.com/prob ...

最新文章

  1. linux下batik-rasterizer.jar生成图片中文乱码
  2. JSP学习笔记(五):日期处理、页面重定向、点击量统计、自动刷新和发送邮件...
  3. 【C++】关于随机函数与概率设置
  4. DotNetCommon-搜集.neter开发常用的功能
  5. MacOS安装zsh插件zsh-autosuggestion(自动命令补全和建议)
  6. 京东联合vivo针对vivo X Note推出先行者计划
  7. Android SDK上手指南:项目清单
  8. 2016年6月 之 《设计模式》
  9. C#不区分大小写的字符串替换(Replace)
  10. 函数参数缺少const导致so无法加载
  11. 淘宝/天猫商品优惠券查询API接口,优惠券API接口
  12. 2021年系统架构设计师考试上午真题与答案
  13. CSDN日报190225——滴滴员工求裁员,阿里不裁员,互联网公司裁员众生相!
  14. 胡乱学Java_遇见类与对象
  15. Havij 1.152 最新破解版
  16. 【网络】什么是HTTPS证书?
  17. 大数据课程设计python_大数据Python编程设计
  18. 聚会活跃气氛小程序-喝酒神器
  19. 第九节-python函数介绍(中)
  20. OkHttp超时时间设置

热门文章

  1. Linux CentOS学习第7天(2018年6月14日)
  2. 修改user-agent爬取数据 遇到的问题
  3. 深入理解uwsgi和gunicorn网络模型
  4. netty高级篇(3)-HTTP协议开发
  5. 【037】Excel 中遍历修改文件(VBA)
  6. VMware View 5.0 策略列表
  7. sha1 java 代码_HMAC-SHA1的java源代码实现
  8. 数据结构实验2-不带头结点的单链表
  9. 大学生免费查题公众号_诺奖作家英文作品赏析尔雅2020年答案查题公众号
  10. a letter and a number