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 遍历可以实现二叉树的先,中 ...
随机推荐
- Unity内生成深度贴图
https://qiita.com/bokkuri_orz/items/08cbaeae6a34fed7f903 https://www.cnblogs.com/sifenkesi/p/4721649 ...
- Shader 的 Blend
Blend SrcAlpha OneMinusSrcAlpha //alpha blending Blend One OneMinusSrcAlpha //premultiplied alpha bl ...
- Salesforce LWC学习(二十四) Array.sort 浅谈
本篇参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort sal ...
- 【小白学PyTorch】8 实战之MNIST小试牛刀
文章来自微信公众号[机器学习炼丹术].有什么问题都可以咨询作者WX:cyx645016617.想交个朋友占一个好友位也是可以的~好友位快满了不过. 参考目录: 目录 1 探索性数据分析 1.1 数据集 ...
- 用于测试 SqlAnalyzer1.01 的21个测试用例
感慨:当年看着 https://www.cnblogs.com/heyang78/p/11451814.html 一文望洋兴叹,如今我也自己做出来了! 21. 原文=select name, cnt ...
- Java多线程--两个线程同时对一个人的年龄进行增加和修改
public class Thread_A extends Thread { Human human; public Thread_A(String name, Human human) { supe ...
- html基础:DOM操作
DOM(Document Object Model 文档对象模型) 一个web页面被封装成一个dom对象,通过dom中的js对页面的标签进行操作 一.获取对象 浏览器页面上右键--检查--consol ...
- Lambda表达式看这篇基本就够用了
本文讯] 2020.05.08 polo 写博不易,尊重知识! Lambda 是java8 引入的一个新特性,闭包,又叫函数式接口,下面介绍下,常用的lambda表达式方式: 所谓的将函数作为一 ...
- Kubernetes K8S之Pod跨namespace名称空间访问Service服务
Kubernetes的两个Service(ServiceA.ServiceB)和对应的Pod(PodA.PodB)分别属于不同的namespace名称空间,现需要PodA和PodB跨namespace ...
- 修改mysql、sqlserver数据库默认用户,不允许为root、sa等
1.mysql cmd进入dos命令,输入mysql -u root -P 1202 -h localhost -p敲回车输入密码 use mysql; 修改用户名root为其他用户 update u ...