Morris遍历

本文详细介绍了Morris遍历这一二叉树遍历方法,它实现了空间复杂度为O(1)、时间复杂度为O(N)的目标。文章提供了Morris遍历的基本流程,以及先序、中序、后序遍历的代码实现,特别指出后序遍历时的特殊处理方法。
摘要由CSDN通过智能技术生成

Morris遍历

Morris遍历是二叉树遍历的另一种方式,做到了空间复杂度为O(1),时间复杂度为O(N)。

1. Morris遍历的流程

当遍历指针cur遍历到某个节点:

  1. 该节点有左孩子,则判断该节点左子树的最右孩子mostRight的right指针
    • 如果最右孩子的right指针为空,说明第一次遍历到该节点,即mostRight.right=null,则令最右孩子的right指针指向自己,即mostRight.right = cur;,然后cur = cur.left;
    • 如果最右孩子的right指针指向自己,说明第二次遍历到该节点,即mostRight.right=cur,则令最右孩子的right指针指向null,即mostRigth.right = null;,然后cur = cur.right;
  2. 该节点无左孩子,cur=cur.right;

通过上述流程,可以看出:非叶子节点,能遍历到两次。而叶子节点,只能遍历到一次。
在这里插入图片描述
则最终遍历到的次序为1242513637
在这里插入图片描述
代码实现

public static void morrisSearch(TreeNode head){
    if(head == null){
        return;
    }
    TreeNode cur = head;
    TreeNode mostRight = null;
    while(cur != null){
        if(cur.left == null){
            cur = cur.right;
        }else{
            mostRight = cur.left;
            while(mostRight.right != null && mostRight.right != cur){
                mostRight = mostRight.right;
            }
            if(mostRight.right == null){
                mostRight.right = cur;
                //cur指针第一次来到该节点
                cur = cur.left;
            }else{//mostRight.right == cur,说明cur指针第二次来到该节点
                mostRight.right = null;
                cur = cur.right;
            }
        }
    }
}

2. 先序遍历

在这里插入图片描述
代码实现

public static void morrisPre(TreeNode head){
    if(head == null){
        return;
    }
    TreeNode cur = head;
    TreeNode mostRight = null;
    while(cur != null){
        if(cur.left == null){
            
            System.out.print(cur.val + " ");
            cur = cur.right;
        }else{
            mostRight = cur.left;
            while(mostRight.right != null && mostRight.right != cur){
                mostRight = mostRight.right;
            }
            if(mostRight.right == null){
                mostRight.right = cur;
                //cur指针第一次来到该节点
                System.out.print(cur.val + " ");
                cur = cur.left;
            }else{//mostRight.right == cur,说明cur指针第二次来到该节点
                mostRight.right = null;
                cur = cur.right;
            }
        }
    }
}

3. 中序遍历

在这里插入图片描述
代码实现

public static void morrisIn(TreeNode head){
    if(head == null){
        return;
    }
    TreeNode cur = head;
    TreeNode mostRight = null;
    while(cur != null){
        if(cur.left == null){
            
            System.out.print(cur.val + " ");
            cur = cur.right;
        }else{
            mostRight = cur.left;
            while(mostRight.right != null && mostRight.right != cur){
                mostRight = mostRight.right;
            }
            if(mostRight.right == null){
                mostRight.right = cur;
                //cur指针第一次来到该节点
                cur = cur.left;
            }else{//mostRight.right == cur,说明cur指针第二次来到该节点
                mostRight.right = null;
                
                System.out.print(cur.val + " ");
                cur = cur.right;
            }
        }
    }
}

4. 后序遍历

后续遍历稍微不同

步骤:

  • 当第二次遍历到非叶节点的时候,逆序打印该节点的左孩子的右边界。(不知道这样表达对不对)。
  • 最后打印整棵二叉树的右边界。
    在这里插入图片描述
    为了保证空间复杂度为O(1),逆序打印的时候不能用栈,先将链表反转,打印后再反转回来。

代码实现

public static void morrisPost(TreeNode head){
    if(head == null){
        return;
    }
    TreeNode cur = head;
    TreeNode mostRight = null;
    while(cur != null){
        if(cur.left == null){
            cur = cur.right;
        }else{
            mostRight = cur.left;
            while(mostRight.right != null && mostRight.right != cur){
                mostRight = mostRight.right;
            }
            if(mostRight.right == null){
                mostRight.right = cur;
                //cur指针第一次来到该节点
                cur = cur.left;
            }else{//mostRight.right == cur,说明cur指针第二次来到该节点
                mostRight.right = null;
                printEdge(cur.left);
                cur = cur.right;
            }
        }
    }
    printEdge(head);
}

//为了使空间复杂度不上升,逆序打印右边界,不能使用栈,而使用反转链表的方式
public static void printEdge(TreeNode head){
    TreeNode tail = reverseList(head);

    TreeNode cur = tail;
    while(cur != null){
        System.out.print(cur.val + " ");
        cur = cur.right;
    }

    //再把链表反转回来
    reverseList(tail);
}

//从单链表的头开始,逆转链表,并返回逆转后单链表的头部。
public static TreeNode reverseList(TreeNode head){
    TreeNode pre = null;
    TreeNode next = null;
    TreeNode cur = head;
    while(cur != null){
        next = cur.right;
        cur.right = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值