【问题标题】:Why does accessing a nil pointer in Go cause an Error in Inorder traversal为什么在 Go 中访问 nil 指针会导致中序遍历出错
【发布时间】:2021-10-25 23:42:38
【问题描述】:

我在 python 中编写了中序遍历,效果很好。

def inOrderTraverse(tree, array):
    if tree is None:
        return None
    inOrderTraverse(tree.left,array)
    array.append(tree.value)
    inOrderTraverse(tree.right,array)
    return array

但是,当我尝试使用 GOlang 应用相同的逻辑时,它不起作用。

type BST struct {
    Value int

    Left  *BST
    Right *BST
}

func (tree *BST) InOrderTraverse(array []int) []int {
    if tree == nil {
        return nil
    }
    (tree.Left).InOrderTraverse(array)
    array = append(array,tree.Value)
    (tree.Right).InOrderTraverse(array)
    return array
}

为了解决这个问题,我编写了 if 语句来防止函数在 tree.Left 为 nil 时被调用。但是我仍然很困惑为什么我的原始代码不起作用。

func (tree *BST) InOrderTraverse(array []int) []int {
    if tree.Left != nil {
        array = tree.Left.InOrderTraverse(array)
    }
    array = append(array,tree.Value)
    if tree.Right != nil {
        array = tree.Right.InOrderTraverse(array)
    }
    return array
}

总而言之,我正在尝试使用与 python 相同的推理在 Go 中编写中序遍历,但它不起作用。我想出了如何让它工作(第三个代码块),但是我仍然不明白为什么第二个代码块不起作用。似乎在 Nil 指针上调用函数会导致错误

【问题讨论】:

    标签: go pointers binary-tree


    【解决方案1】:

    有几点:

    在您的第二个代码块中,它不起作用的原因是结果被丢弃:

     // (tree.Left).InOrderTraverse(array) // the return result is ignored
     array = (tree.Left).InOrderTraverse(array) // capture it like so
    

    Python 使用按引用传递; Go 按值传递。因此,它可能会变得很棘手,尤其是在 Go 中修改 slices 之类的内容时。

    由于您已经返回了遍历的结果,因此传入 array 实际上是多余的。


    将所有这些组合在一起以修复左右遍历 - 并使用返回变量 result

    func (tree *BST) InOrderTraverse() (result []int) {
        if tree == nil {
            return // implicitly returns empty `result`
        }
    
        result = append(result, (tree.Left).InOrderTraverse()...)
        result = append(result, tree.Value)
        result = append(result, (tree.Right).InOrderTraverse()...)
    
        return // implicitly returns `result`
    }
    

    工作示例:https://play.golang.org/p/AUvgZTABiU9


    编辑

    Go “按引用传递” 实现 - 在调用之间传递 results 切片 - 看起来与您的 python 实现非常相似:

    func (tree *BST) InOrderTraverse(result *[]int) {
        if tree == nil {
            return
        }
    
        (tree.Left).InOrderTraverse(result)
    
        *result = append(*result, tree.Value)
    
        (tree.Right).InOrderTraverse(result)
    }
    

    https://play.golang.org/p/Pp9-4-y-lmE

    注意:这里需要*[]int(即指向[]int的指针),因为在递归过程中切片容量会发生变化。切片实际上只是一个header with a backing array - 所以虽然函数可以更改切片的元素 - 即使按值复制 - 它不能使切片缩小或增长(就像这里的情况一样)。传递指针允许将切片重新分配给可能更大的后备数组。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多