Morris遍历 - 如何检查是否到达叶节点?

时间:2017-11-13 13:17:23

标签: algorithm binary-tree

在二叉树的morris遍历中,它使用每个正确的叶节点来构建到当前节点的连接。

假设我们以预先排序的方式遍历树,当到达叶节点时,我们如何判断是否遇到叶节点?

例如。我们不能使用以下行检查: if(null == node.left&& null == node.right)

因为由于morris算法,node.right指向当前节点。

一个好方法是我们总是使用TreeNode对象中的字段将访问过的节点标记为已访问,但是如果我们没有这个字段,那么在许多情况下会怎样?

任何人都知道如何检查您是否到达叶节点?感谢。

此致 千斤顶

3 个答案:

答案 0 :(得分:1)

更新:我想出了关于如何使用Morris Traversal检测叶节点的更清晰的解释。所有叶子都是:

  1. 恰好是叶子是树上最右边的叶子。要检测到它,您需要检查curr left == nilcurr.right == nil
  2. 其余所有叶子都是人为设置的指向其他节点的链接。如果您考虑一下,这是有道理的:Morris Traversal不能以任何其他方式从叶节点回溯。因此,其余所有叶子是前任/已经连接到当前节点。

如果这仍然对您没有意义,请查看此Morris遍历的可视化,并注意,除一片叶子外,所有叶子都是“已连接”节点+在树的最后端是一个:

enter image description here


这很棘手,但有可能,这是Go中的代码,我在保持O(1)的同时测试了很多棘手的边缘情况:

func getLeafs(node *TreeNode) []int {
    var leafs []int
    var pre *TreeNode // predecessor of the current node
    curr := node

    for curr != nil {
        if curr.Left == nil {
            if curr.Right == nil { // additional check needed
                leafs = append(leafs, curr.Val)
            }
            curr = curr.Right
            continue
        }

        // curr.Right != nil
        pre = curr.Left
        for pre.Right != nil && pre.Right != curr {
            pre = pre.Right
        }

        if pre.Right == nil {
            pre.Right = curr
            curr = curr.Left
            continue
        }

        // pre.Right == curr
        pre.Right = nil
        if pre.Left == nil { // tricky part! we are not using curr here
            leafs = append(leafs, pre.Val)  // we are actually using pre
        }
        curr = curr.Right
    }

    return leafs
}

基本上,您需要在两个地方签入:

  1. 与标准的Morris遍历一样,您先检查curr.Left == nil,然后检查curr.Right == nil
  2. 棘手的部分:当curr节点具有指向pre节点的链接时,您无需使用curr节点。

答案 1 :(得分:0)

可以通过标记已访问的节点来简单地解决问题。

因此叶子节点可以通过以下方式证明: if(null == node.left&&(null == node.right || node.right.isLinked)) 其中“isLinked”是由于Morris算法而由每个右叶节点链接的节点。

好的,它再次回到我的问题,我们怎么能有关于“isLinked”的记录?

我们可以通过设置添加所有与morris相关的节点来轻松解决它。

所以它会是: if((null == node.left&& null == node.right)|| set.contains(node.right))

答案 2 :(得分:0)

就像Jack回答的那样,它是要检查是否(null == node.left &&(null == node.right || node.right.isLinked)。在python中,您可以在将其前任链接到curr之前为其设置setattr。

在此处分享我的代码

def getLeaf(self, root):
    curr = root
    while curr != None:
        if not curr.left and (not curr.right or hasattr(curr, 'isLinked')):
            print("I am a leaf ", curr.val)
        if curr.left is None:
            curr = curr.right
        else:
            prec = curr.left
            while prec.right != None and prec.right != curr:
                prec = prec.right
            if prec.right is None:
                prec.right = curr
                setattr(prec, 'isLinked', True)
                curr = curr.left
            else:
                curr = curr.right