Morris遍历中的先序、中序、后序实现

Morris遍历

先介绍一下Morris遍历的具体过程,至于先序、中序和后序就是在遍历中选择不同时机进行打印。

在Morris遍历中,我们假设当前节点为 cur,只要当前节点的左节点存在,顺着左节点的右边一直走到它的最右边界节点,

  • 如果是第一次遍历到这个最右边界节点,那么这个边界节点的 right 应该指向 None,这里做一个标记,将它的 right 不再指向 None,改为指向当前的 cur 节点, 此时cur 下一步就应该来到cur的左节点;
  • 如果不是第一次来到这个最右边界节点,那么最右边界的 right 应该是指向当前的 cur ,此时先将right恢复为指向 None, cur的下一步来到 cur 的右节点;

上面两条中,关键的一点就在于如何判断是不是第一次来到这个最右边界,所以将最右边界的 right 指向作一个修改,通过这个判断是不是第一次来到最右边界,从而决定接下来的 cur 的走向。毫无疑问,如果是第一次来到,那么 cur 往左节点走,一定会再次来到这个最右边界;如果不是第一次来到,那么接下来 cur 会往右走,一定不会再来到这个左节点的最右边界;

这是左节点存在时候的走向,如果左节点不存在,那就更简单了,cur 直接去往右节点,再继续判断。最后如果连右节点都不存在了,说明当前树已经遍历结束。整个流程结束。

整个遍历遵循先左再右的原则,左边遍历结束后,才会前往右边。

# 纯morris遍历,不带任何输出
def morris_tree(head):
    if head == None: return None

    cur = head
    while (cur != None):
        if cur.left != None:
        	most_right = cur.left
            while (most_right.right != None and most_right.right is not cur): # 找到它的左子树的最右边界
                most_right = most_right.right

            if most_right.right == None: # 此时表示cur节点是第一次
                most_right.right = cur
                cur = cur.left
                continue   # 中断当前的while循环,进行下一次while
            else: # 表明这是第二次访问cur节点了
                most_right.right = None

        cur = cur.right

先序遍历:

从最简单的递归遍历出发,仔细揣摩真个递归过程,其实不同的遍历顺序实质是选择不同的遍历时机进行输出打印,拿先序遍历来说,选择在第一次来到当前节点的时候,打印输出,就是先序遍历;中序就是选择在第二次时候打印,后序就是第三次。代码如下:

def process(head):

    if head == None:
        return head

    print(head.value) # 先序
    
    process(head.left)
    # print(head.value)  # 中序
    
    process(head.right)
    # print(head.value)  # 后序

同样的在Morris遍历中,我们选择在第一次来到当前节点的时候打印,最终就是先序遍历;而在Morris遍历中,根据当前节点的左子树的最右边界的 right 是否指向当前节点来判断是第几次来到当前节点,如果不存在左子树的话,那么就要立即打印;
代码如下:

def morris_tree_preOrder(head):
    if head == None: return None

    cur = head

    while (cur != None):
        most_right = cur.left

        if cur.left != None:
            while (most_right.right != None and most_right.right is not cur):
                most_right = most_right.right

            if most_right.right == None:
                most_right.right = cur
                print(cur.value) # 如果cur左子树存在,它的左子树的最右边界没有指向cur也就是指向None的时候,表示它是第一次来到这个节点
                cur = cur.left
                continue
            else:
                most_right.right = None
        else:
            print(cur.value) # cur的左子树不存在,那么它再也不会回到cur,第一次也是最后一次

        cur = cur.right

中序遍历

中序遍历也是同样道理,当前节点的左子树不存在或者是第二次来到当前节点时打印;

def morris_tree_inOrder(head):

    if head == None: return None

    cur = head
    while (cur != None):
        most_right = cur.left

        if most_right != None:
            while (most_right.right != None and most_right.right is not cur):
                most_right = most_right.right

            if most_right.right == None:
                most_right.right = cur
                cur = cur.left
                continue
            else:
                most_right.right = None
                print(cur.value)
        else:
            print(cur.value) # cur的左子树不存在,那么它再也不会回到cur,第一次也是最后一次
            
        cur = cur.right

后序遍历

后序遍历稍微有些不同,在Morris遍历中,顺着每个节点的左子树,可以把它分成若干个右边界,我们选择在每次左子树存在的情况下,逆序打印它的右边界,就可以实现后序遍历;

def morris_tree_postOrder(head):
    if head == None: return None

    cur = head
    while (cur != None):
        most_right = cur.left

        if cur.left != None:
            while (most_right.right != None and most_right.right is not cur): # 找到它的左子树的最右边界
                most_right = most_right.right

            if most_right.right == None: # 此时表示cur节点是第一次
                most_right.right = cur
                cur = cur.left
                continue   # 中断当前的while循环,进行下一次while
            else: # 表明这是第二次访问cur节点了
                most_right.right = None
                printEdge(cur.left) # 第二次访问cur节点时,逆序打印cur的左子树的右边界

        cur = cur.right
    printEdge(head)  # 打印头结点的右边界


# 打印右边界
def printEdge(head):
    tail = reverseEdge(head)
    cur = tail
    while (cur != None):
        print(cur.value)
        cur = cur.right

    reverseEdge(tail)


# 反转链表
def reverseEdge(head):

    pre = None
    while head != None:
        tmp = head.right
        head.right = pre
        pre = head
        head = tmp

    return pre

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值