为什么我的Go指针接收器不会导致更新?

时间:2013-11-06 21:12:11

标签: go

我想请一些关于Go指针接收器如何工作的帮助。

我在下面有一个二进制搜索树的例子,希望能帮我解释一下。

package main

import "fmt"

type Node struct {
  key         int
  left, right *Node
}

func NewNode(key int) *Node {
  return &Node{key, nil, nil}
}

type BST struct {
  root *Node
}

func NewBinarySearchTree() *BST {
  return &BST{nil}
}

func (t *BST) Insert(key int) {
  if t.root == nil {
    t.root = NewNode(key)
    return
  }
  var node = t.root
  for {
    if key < node.key {
      if node.left == nil {
        node.left = NewNode(key)
        return
      } else {
        node = node.left
      }
    } else {
      if node.right == nil {
        node.right = NewNode(key)
        return
      } else {
        node = node.right
      }
    }
  }
}

func inorder(node *Node) {
  if node == nil {
    return
  }
  inorder(node.left)
  fmt.Print(node.key, " ")
  inorder(node.right)
}

func main() {
  tree := NewBinarySearchTree()
  tree.Insert(3)
  tree.Insert(1)
  tree.Insert(2)
  tree.Insert(4)
  inorder(tree.root) // 1 2 3 4
}

然而,在我写完之后,我想我可以简化我的插入功能,如下所示:

func (t *BST) Insert2(key int) {
  var node *Node
  node = t.root
  for node != nil {
    if key < node.key {
      node = node.left
    } else {
      node = node.right
    }
  }
  node = NewNode(key)
}

但是,这样做,树永远不会更新。 我的想法是......

  • 在第一个插入时,根节点将为nil。
  • 所以引用t.root的局部变量节点也将是nil
  • 因此将跳过for循环。
  • node = NewNode(key)t.root = NewNode(key)
  • 具有相同的效果

我的Insert2方法在哪里出错?有没有办法可以调整?

2 个答案:

答案 0 :(得分:3)

node = NewNode(key)

该行不会更改树。该行更改了局部变量node;在此行之后,node指向不同的节点,但它用于指向的对象不受影响。要插入树中,您必须分配到t.rootnode.leftnode.right

答案 1 :(得分:3)

您似乎对指针的使用感到困惑。

执行node = t.root后,您只需将node指向t.root点即可。

稍后,当您执行node = NewNode(key)时,您会node指向新创建的项目,这不是您想要的;你想让t.root指向那个新项目。

由于您打算修改类型为*Noderootleftright)的变量,我们需要一个指向它们的指针,因此需要一个类型的变量**Node,还有一个间接层。

您可以先将node指向t.rootnode := &t.root的地址,然后继续循环播放。

您可以尝试以下内容:

func (t *BST) Insert3(key int) {
    node := &t.root
    for *node != nil {
        if key < (*node).key {
            node = &(*node).left
        } else {
            node = &(*node).right
        }
    }
    *node = NewNode(key)
}

注意我们在检查循环上的地址时使用间接操作符*来访问引用的数据,以及密钥。

在函数的最后,*node = NewNode(key)执行您最初打算执行的操作;您将新创建的项目分配给根,左或右指针。