Morris遍历
Morris遍历
一种遍历二叉树的方式,并且时间复杂度O(N),额外空间复杂度O(1)
通过利用原树中大量空闲指针的方式,达到节省空间的目的
Morris遍历可以改前中后序的树遍历
思路:
创建一个当前节点cur 等于 head节点,再创建一个mostRight节点 表示最右节点
mostRight 当为空的时候表示是第一次来,如果mostRight 指向的是 cur 节点的位置,则代表已经来过一次了,现在是第二次,第二次来的时候直接mostRight置空就可以了
总流程是,当 cur 不为空的时候,mostRight 来到左孩子的位置,如果右孩子存在且是第一次来到这个节点,mostRight 遍历到最后
然后再判断,当前节点的右孩子是否为空,如果是空就把 mostRight 的右孩子指向 cur ,表示自己已经来过了一次,然后 cur 来到他左孩子的位置,继续循环的找。
如果当 cur 来到了 最右结点,发现右孩子是被修改过的,也就是之前修改成cur的指针,然后 cur 就会回到上次的 cur 的位置,回去之后,再把刚刚的那个结点右孩子改为空
就像一个线索一样,不断的执行这些过程,直到完成整个遍历
class Node
{
public:
Node(int data) :value(data){}
int value;
Node *left;
Node *right;
}; void morris(Node *head)
{
if (head == NULL)
{
return;
}
Node *cur = head;
Node *mostRight = NULL;
while (cur != NULL)
{
mostRight = cur->left;
if(mostRight != NULL)
{
while(mostRight->right != NULL && mostRight->right != cur)
{
mostRight = mostRight->right;
}
if (mostRight->right == NULL)
{
mostRight->right = cur;
cout << cur->value << " ";
cur = cur->left;
continue;
}
else {
mostRight->right = NULL;
}
}
cout << cur->value << " ";
cur = cur->right;
}
}
Morris改先序遍历
思路:
先序遍历的打印结果只需要把第一次遍历到的位置都输出,也就是除了第二次来到的位置都打印,就是先序遍历
void morrisPre(Node *head)
{
if (head == NULL)
{
return;
}
Node *cur = head;
Node *mostRight = NULL;
while (cur != NULL)
{
mostRight = cur->left;
if (mostRight != NULL)
{
while (mostRight->right != NULL && mostRight->right != cur)
{
mostRight = mostRight->right;
}
if (mostRight->right == NULL)
{
mostRight->right = cur;
//第一次来了,直接返回上去
cout << cur->value << " ";
cur = cur->left;
continue;
}
else {
//第二次来到的
mostRight->right = NULL;
}
}
else {
//第一次来到的
cout << cur->value << " ";
}
cur = cur->right;
}
}
Morris改中序遍历
思路:
中序遍历,只需要把 能第二次来到的位置,第二次打印出来,第一次不打印,然后把只能来一次的位置第一次打印出来,就是中序遍历
void morrisMid(Node *head)
{
if (head == NULL)
{
return;
}
Node *cur = head;
Node *mostRight = NULL;
while (cur != NULL)
{
mostRight = cur->left;
if (mostRight != NULL)
{
while (mostRight->right != NULL && mostRight->right != cur)
{
mostRight = mostRight->right;
}
if (mostRight->right == NULL)
{
mostRight->right = cur;
cur = cur->left;
continue;
}
else {
mostRight->right = NULL;
}
}
cout << cur->value << " ";
cur = cur->right;
}
}
Morris后序遍历
思路:
把能进行二次遍历的结点 的右子树 逆序打印,最后再将 整个的右子树 逆序打印
Node* reverseEdge(Node *from)
{
Node *pre = NULL;
Node *next = NULL;
while (from != NULL)
{
next = from->right;
from->right = pre;
pre = from;
from = next;
}
return pre;
} void printEdge(Node *head)
{
Node *tail = reverseEdge(head);
Node *cur = tail;
while (cur != NULL)
{
cout << cur->value << " ";
cur = cur->right;
}
reverseEdge(tail);
} void morrisPos(Node *head)
{
if (head == NULL)
{
return;
}
Node *cur = head;
Node *mostRight = NULL;
while (cur != NULL)
{
mostRight = cur->left;
if (mostRight != NULL)
{
while (mostRight->right != NULL && mostRight->right != cur)
{
mostRight = mostRight->right;
}
if (mostRight->right == NULL)
{
mostRight->right = cur;
cur = cur->left;
continue;
}
else {
mostRight->right = NULL;
printEdge(cur->left);
}
}
cur = cur->right;
}
printEdge(head);
}
Morris遍历的更多相关文章
- 二叉树的遍历(递归,迭代,Morris遍历)
二叉树的三种遍历方法: 先序,中序,后序,这三种遍历方式每一个都可以用递归,迭代,Morris三种形式实现,其中Morris效率最高,空间复杂度为O(1). 主要参考博客: 二叉树的遍历(递归,迭代, ...
- 二叉树的遍历(递归,迭代,Morris遍历)
二叉树的遍历: 先序,中序,后序: 二叉树的遍历有三种常见的方法, 最简单的实现就是递归调用, 另外就是飞递归的迭代调用, 最后还有O(1)空间的morris遍历: 二叉树的结构定义: struct ...
- 【转载】Morris遍历二叉树 & BST(二叉搜索树) Traverse & 空间O(1) 时间O(n)
因为做一道Leetcode的题目(前面博客有:link),需要用Space O(1)空间复杂度来中序遍历树, 看了Discuss,也上网搜了一下,发现空间O(1)可以用 Morris遍历的方法.方法介 ...
- 二叉树的Morris遍历
二叉树的遍历,除了上篇文章中的传统递归和使用的栈结构的非递归方式,还有如下这种Morris遍历方式,该算法的构思非常巧妙:利用前驱空闲的rightChild指针指向当前节点,形成一个环.时间复杂度和前 ...
- 算法进阶面试题03——构造数组的MaxTree、最大子矩阵的大小、2017京东环形烽火台问题、介绍Morris遍历并实现前序/中序/后序
接着第二课的内容和带点第三课的内容. (回顾)准备一个栈,从大到小排列,具体参考上一课.... 构造数组的MaxTree [题目] 定义二叉树如下: public class Node{ public ...
- 经典算法 Morris遍历
内容: 1.什么是morris遍历 2.morris遍历规则与过程 3.先序及中序 4.后序 5.morris遍历时间复杂度分析 1.什么是morris遍历 关于二叉树先序.中序.后序遍历的递归和非递 ...
- 面试中很值得聊的二叉树遍历方法——Morris遍历
Morri遍历 通过利用空闲指针的方式,来节省空间.时间复杂度O(N),额外空间复杂度O(1).普通的非递归和递归方法的额外空间和树的高度有关,递归的过程涉及到系统压栈,非递归需要自己申请栈空间,都具 ...
- 【数据结构与算法】二叉树的 Morris 遍历(前序、中序、后序)
前置说明 不了解二叉树非递归遍历的可以看我之前的文章[数据结构与算法]二叉树模板及例题 Morris 遍历 概述 Morris 遍历是一种遍历二叉树的方式,并且时间复杂度O(N),额外空间复杂度O(1 ...
- Morris 遍历实现二叉树的遍历
Morris 遍历实现二叉树的遍历 作者:Grey 原文地址: 博客园:Morris 遍历实现二叉树的遍历 CSDN:Morris 遍历实现二叉树的遍历 说明 Morris 遍历可以实现二叉树的先,中 ...
随机推荐
- 使用script打开页面
<script src="x" onerror=javascript:window.open("http://192.168.38.1/csrf.html" ...
- Redis锁实现防重复提交和并发问题
@Slf4j @Component public class RedisLock { public static final int LOCK_EXPIRE = 5000; @Autowired pr ...
- Google Analytics谷歌分析事件之非互动事件
非互动事件官方的解释如下 “非互动”一词是指可选的布尔值参数,此参数可以传递到用于发送事件命中的方法.通过此参数,您可以确定要如何为网站上包含事件衡量的网页定义跳出率.例如,假设您的首页上内嵌有一个视 ...
- Spine学习一 -渲染组件
一共有四个播放的组件: SkeletonAnimation:有点儿类似于 unity的 Animation,挂上一个spine资源,就可以跑了 SkeletonRenderer:SkeletonAni ...
- 数据库系统第六章【关系数据理论】(B站视频)
目录 数据库系统第六章[关系数据理论](B站视频) 一.前言 二.规范化 函数依赖 三种分类 如何确定函数依赖? 平凡函数依赖vs非平凡函数依赖 完全函数依赖vs部分函数依赖 传递函数依赖 码 超码 ...
- Google Code Jam 2020 Round1B Join the Ranks
题意 给你一个形如\(1,2,\cdots,R,1,2,\cdots,R,1\cdots\)的序列,共重复\(C\)次.你每次可以选择一个区间\([L,R]\)将其平移到序列首部,最终使得序列具有\( ...
- Codeforces 1321C Remove Adjacent
题意 给你一个字符串,字符\(s_i\)可以被伤处当且仅当\(s_{i-1}=s_i-1\)或\(s_{i+1}=s_i-1\).问最多能删几个字符. 解题思路 其实,有个很简单的做法就是从\(z\) ...
- webpack 多页面构建
目标: 基于webpack支持react多页面构建(不用gulp,gulp-webpack 构建速度太慢[3]), generator-react-webpack 对单页面支持很好,但对多页面,需要改 ...
- 从String中移除空白字符的多种方式!?
字符串,是Java中最常用的一个数据类型了.我们在日常开发时候会经常使用字符串做很多的操作.比如字符串的拼接.截断.替换等. 这一篇文章,我们介绍一个比较常见又容易被忽略的一个操作,那就是移除字符串中 ...
- ORA-00119: ORA-00132: 解决办法 -九五小庞
问题描述: 1. em打开中提示 https://localhost:1158/em/console/database/instance/repDown?target=orclweng&typ ...