【问题标题】:What is the correct way to implement a stack in Go so that it will store structs?在 Go 中实现堆栈以存储结构的正确方法是什么?
【发布时间】:2015-07-30 16:10:11
【问题描述】:

我正在尝试创建一个堆栈来存储一系列霍夫曼树结构。目前我正在使用我在 github 上找到的实现。

package util

type item struct {
    value interface{}
    next  *item
}

//Stack the implementation of stack
//this stack is not thread safe!
type Stack struct {
    top  *item
    size int
}
// Basic stack methods...

问题是,当我将 Huffman 树结构存储在堆栈中时,我无法使用 Huffman 树的任何字段,例如左/右孩子。

package huffmantree

type HuffmanTree struct {
    freq   int
    value  byte
    isLeaf bool
    left   *HuffmanTree
    right  *HuffmanTree
    code   []bool
    depth  int
}

我应该如何在 Go 中实现一个堆栈来正确存储结构并允许访问它们的字段?

编辑: 我尝试用huffmantree.HuffmanTree(huffmantree 结构)替换interface {} 部分并收到以下错误消息:

can't load package: import cycle not allowed
package github.com/inondle/huffman/util
    imports github.com/inondle/huffman/huffmantree
    imports github.com/inondle/huffman/util
import cycle not allowed

我的猜测是 huffmantree 类导入了 util 包,而堆栈必须导入 huffmantree 包,所以存在某种冲突?有谁知道出了什么问题?

【问题讨论】:

  • 不使用空接口{},而是使用实际结构。因此,在您的示例中:值 HuffmanTree。
  • go 中的通用版本是不可能的。
  • @0x434D53 我尝试用我的 huffmantree 结构替换接口{},但它导致了一个错误,上面写着can't load package: import cycle not allowed

标签: types go stack


【解决方案1】:

go 中实现堆栈的正确方法是使用切片。

stack := []*HuffmanTree{}

您可以使用append 推入堆栈,并通过写入弹出:

v, stack := stack[len(stack)-1], stack[:len(stack)-1]

如果您愿意,可以将其封装成自己的类型,但切片更容易理解。

type Stack []*HuffmanTree{}

func NewStack() *Stack {
    var s []*HuffmanTree
    return (*Stack)(&s)
}

func (s *Stack) Pop() *HuffmanTree {
   if len(*s) == 0 {
      return nil
    }
    v = (*s)[len(*s)-1]
    *s = (*s)[:len(*s)-1]
    return v
}

func (s *Stack) Push(h *HuffmanTree) {
    *s = append(*s, h)
}

正如 icza 所观察到的,如果堆栈的寿命比 HuffmanTree 对象长,您可能希望将堆栈中刚刚弹出的条目归零,以允许垃圾收集器收集未引用的对象。

【讨论】:

  • 我重新实现了封装在自己类型中的堆栈,但它与所有其他 Tree 方法一起在 HuffmanTree 文件中。我这样做是因为如果我尝试构建两个相互导入的包(huffmantree 使用 util,而 util 使用 huffmantree),那么它会给我一个导入周期错误。不过,从未导出的堆栈方法到导出的 Huffman Tree 方法看起来很奇怪。我做错了什么还是我必须在 huffmantree 代码中包含我的堆栈代码?
  • @lnondle 名为“util”的包表明您的代码组织可以改进(阅读:blog.golang.org/package-names)。我希望堆栈与您的 HuffmanTree 存在于同一个包中,可能有更好的名称(也许:huffman.Tree、huffman.TreeStack),但不提供堆栈并让调用者自己编写(因为它很简单)也是诱人。但是,如果不了解您的代码和用例,就很难给出一般性建议。
  • 请注意,从切片堆栈中弹出一个元素也应该用零值填充弹出元素的空间,因为底层数组仍将保存该值并防止其内存被回收垃圾收集器。对于原始值类型(例如int),不归零是可以的,但对于也有指针字段等的指针、映射、切片或结构则不行。
  • @icza 是真的。我添加了一条评论。
猜你喜欢
  • 1970-01-01
  • 2015-11-15
  • 2015-12-20
  • 1970-01-01
  • 2017-06-11
  • 1970-01-01
  • 1970-01-01
  • 2016-08-13
  • 2014-09-17
相关资源
最近更新 更多