【问题标题】:assigning nil to pointer将 nil 分配给指针
【发布时间】:2013-12-30 05:59:19
【问题描述】:

我正在尝试对列表实现 delete() 方法(无 HEAD ref)

我发现可以将参数修改为结构体。

func (l *LinkedList) Delete(n *Node) {
    if n.next == nil {
        n = nil
    } else {
        current := &n
        *n = *n.next
        *current = nil
    }

}

“else”部分工作正常,但删除最后一个节点不会修改列表

尝试使用

*n = nil

然后我有编译错误。

不能在赋值中使用 nil 作为类型节点

在这个操场上完成代码:

http://play.golang.org/p/Dhzyd7QHEw

【问题讨论】:

  • 不确定这是否相关,但您查看过内置列表吗? golang.org/pkg/container/list
  • 是的,这更像是如何实现特定的删除案例。谢谢

标签: pointers go


【解决方案1】:

你只是做错了。我的意思是从单链表中删除经典元素。正确的方式:

func (l *LinkedList) Delete(n *Node) {
    // if we want to delete the head element - just move the head pointer
    if l.head == n {
        l.head = n.next
        return
    }
    // otherwise find previous element to the one we are deleting
    current := l.head
    for current != nil && current.next != n {
        current = current.next
    }
    // and move that previous element next pointer to the next element
    if current != nil {
        current.next = n.next
    }
}

https://play.golang.org/p/_NlJw_fPWQD

那么你的例子有什么问题?在您的 Delete 函数中,您正在接收指向某个节点的指针。这个指针对于你的函数来说是本地的,它就像一个局部变量。将 nil 分配给函数内的局部变量并不重要。外面 - 没有人会看到这样的任务。您想要做的 - 是更改上一个列表项的 next 指针。这样该项目将不再在列表中。 GC 会移除实际分配的内存。

更新:

由于 go 指针是“真正的”指针,这可以通过使用额外的间接级别来实现,而无需去除头部的特殊情况,正如 Linus 在他著名的 TED talk 中所建议的那样(以及更早的 slashdot Q&A -请参阅“最喜欢的黑客”问题):

func (l *LinkedList) Delete(n *Node) {
    // initialize indirect with the address of a head pointer
    indirect := &(l.head)
    // until indirect has address of a pointer to the node we're deleting
    for *indirect != n {
        // check that it's not the end of the list
        if (*indirect).next == nil {
            // the node we're tryign to delete is not in the list
            return
        }
        // set indirect to the address of the next pointer
        indirect = &(*indirect).next
    }
    // indirect has address of a pointer we need to modify to delete the node
    *indirect = n.next
}

https://play.golang.org/p/hDy3hB5LUME

IMO 的两级间接引用比删除 head 元素的简单特例更难理解,但 Linus 并不完全是像我这样的普通开发者 :)

【讨论】:

  • 感谢您的回答是的,使用 head 很容易,部分原始问题是如果您只有要删除的节点的引用(无 head)void delete_node(node* node) { node->Data = node->Next->Data; node* temp = node->Next->Next; delete(node->Next); node->Next = temp; } 基本上我该怎么做'正在尝试这样做,以了解指针的工作原理。 [链接]stackoverflow.com/questions/9362896/…
  • @MarianoDM 你不能用没有头的 single 链表来做到这一点。您编写的 C 代码仅适用于删除非最后一个元素的情况。
  • @Kluyg 我认为如果你想删除头节点这不起作用
  • @Kluyg 那么有没有像 Linus 在 golang 中建议的那样实现这个? cdn-images-1.medium.com/max/800/1%2AGHFLYFB3vDQeakMyUGPglw.png
  • @SasanRose 当然可以,go 有真正的指针,所以你可以这样做:play.golang.org/p/7lQMDjRoEjPIMO 两级间接比 head 元素的简单特殊情况更难理解,但 Linus 不这么认为:)
猜你喜欢
  • 2013-12-10
  • 2017-02-02
  • 2017-07-30
  • 2014-08-23
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多