ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Morris算法

2021-05-14 20:52:09  阅读:287  来源: 互联网

标签:node 结点 right cur res 算法 Morris null


参考:https://www.cnblogs.com/blzm742624643/p/10021388.html

一、算法介绍

  Morris算法充分利用了二叉树叶子结点下的空间,从而可以在时间复杂度为O(N),空间复杂度为O(1)的条件下,前中后序遍历二叉树(不是完全二叉树也可以使用)。

  而常见的遍历二叉树的方法为递归和栈迭代,这两种方法的时间复杂度虽然也为O(N),但是空间复杂度需要O(N),因此Morris算法可以极大节省空间。

二、算法原理

  首先来到当前结点记为cur。

  1.如果cur无左孩子,cur向右移动。

  2.如果cur有左孩子,那么找到cur左子树的最右的结点,记为mostRight。

    2.1如果mostRight的right指针指向空,则让其指向cur,然后cur向左移动

    2.2如果mostRight的right指针指向cur,让其指回空,然后cur向右移动。

三、算法实现

  困难之处在于在遍历的子结点的时候如何重新返回其父结点?在Morris遍历算法中,通过修改叶子结点的左右空指针来指向其前驱或者后继结点来实现的。   1. 中序遍历     如果当前结点pNode的左孩子为空,那么输出该结点,并把该结点的右孩子作为当前结点;     如果当前结点pNode的左孩子非空,那么就找出该结点在中序遍历中的前驱结点pPre     当第一次访问该前驱结点pPre时,其右孩子必定为空,那么就将其右孩子设置为当前结点,以便根据这个指针返回到当前结点pNode中,并将当前结点pNode设置为其左孩子;     当该前驱结点pPre的右孩子为当前结点,那么就输出当前结点,并把前驱结点的右孩子设置为空(恢复树的结构),将当前结点更新为当前结点的右孩子     重复以上两步,直到当前结点为空。
var inOrder3= function (root) {
    if(root === null)
        return;
    let cur = root;
    let res = [];
    while(cur){
        if(cur.left === null){
            res.push(cur.val);
            cur = cur.right;
        }else{
            let node = cur.left;
            while(node!==null && node.right !== null && node.right !== cur){
                node=node.right;
            }
            if(node.right === null){
                node.right = cur;
                cur = cur.left;
            }else{
                node.right = null;
                res.push(cur.val);
                cur = cur.right;
            }
        }
    }
    return res;
};
  2.前序遍历     与中序遍历类似,区别仅仅是输出的顺序不同。
var preOrder3= function (root) {
    if(root == null)
        return;
    let cur = root;
    let res = [];
    while(cur){
        if(cur.left === null){
            res.push(cur.val);
            cur = cur.right;
        }else{
            let node = cur.left;
            while(node!==null && node.right !== null && node.right !== cur){
                node=node.right;
            }
            if(node.right === null){
                res.push(cur.val);
                node.right = cur;
                cur = cur.left;
            }else{
                node.right = null;
                cur = cur.right;
            }
        }
    }
    return res;
};
3.后序遍历(正确性还有待验证) // 先建立一个临时结点dummy,并令其左孩子为根结点root,将当前结点设置为dummy; // 如果当前结点的左孩子为空,则将其右孩子作为当前结点; // 如果当前结点的左孩子不为空,则找到其在中序遍历中的前驱结点 // 如果前驱结点的右孩子为空,将它的右孩子设置为当前结点,将当前结点更新为当前结点的左孩子; // 如果前驱结点的右孩子为当前结点,倒序输出从当前结点的左孩子到该前驱结点这条路径上所有的结点。 // 将前驱结点的右孩子设置为空,将当前结点更新为当前结点的右孩子。 // 重复以上过程,直到当前结点为空。
var postOrder3= function (root) {
    if(root === null)         return;     let cur = root;     let res = [];     let right = [];     while(cur){         if(cur.left === null){             cur = cur.right;         }else{             let node = cur.left;             let tmp=[];             while(node!==null && node.right !== null && node.right !== cur){                 tmp.push(node.val);                 node=node.right;             }             if(node.right === null){                 node.right = cur;                 cur = cur.left;             }else{                 //倒叙遍历cur.left -> node                  res.push(...tmp.reverse())                                 if(tmp.length>0 || right.length>0){                     right.push(cur.val);                 }                 node.right = null;                 cur = cur.right;             }         }     }     //最后再加上最右边界     res.push(...right.reverse())     return res; }

 

标签:node,结点,right,cur,res,算法,Morris,null
来源: https://blog.51cto.com/u_15201483/2776356

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有