我在Go中构建了一个简单的队列。它使用内部切片来跟踪其元素。通过附加到切片将元素推送到队列中。我想删除.Pop()
中的第一个元素来实现elements
。
在许多其他语言中,“弹出”列表的第一个元素是单行,这使我相信下面的实现是草率和冗长的。还有更好的方法吗?
type Queue struct {
elements []interface{}
}
func (queue *Queue) Push(element interface{}) {
queue.elements = append(queue.elements, element)
}
func (queue *Queue) Pop() interface{} {
element := queue.elements[0]
if len(queue.elements) > 1 {
queue.elements = queue.elements[1:]
} else {
queue.elements = make([]interface{}, 0)
}
return element
}
请注意,如果Queue
我希望len(queue.elements) == 0
恐慌。我没有检查边界,这不是疏忽。
答案 0 :(得分:28)
你试过这些吗?
从队列中弹出
x, a = a[0], a[1:]
从堆栈弹出
x, a = a[len(a)-1], a[:len(a)-1]
推
a = append(a, x)
答案 1 :(得分:4)
如果你想要一个环形缓冲区或FIFO结构,那么在@Everton的答案中使用切片将导致垃圾收集问题,因为底层数组可能会无限增长。
如果你不介意有限的大小,最简单的方法就是使用一个对并发访问也安全的通道。这是一个常见的成语,你通常不会在下面的类型中包装它。
例如(Playground)
package main
import "fmt"
type Queue struct {
elements chan interface{}
}
func NewQueue(size int) *Queue {
return &Queue{
elements: make(chan interface{}, size),
}
}
func (queue *Queue) Push(element interface{}) {
select {
case queue.elements <- element:
default:
panic("Queue full")
}
}
func (queue *Queue) Pop() interface{} {
select {
case e := <-queue.elements:
return e
default:
panic("Queue empty")
}
return nil
}
func main() {
q := NewQueue(128)
q.Push(1)
q.Push(2)
q.Push(3)
fmt.Printf("Pop %d\n", q.Pop())
fmt.Printf("Pop %d\n", q.Pop())
fmt.Printf("Pop %d\n", q.Pop())
fmt.Printf("Pop %d\n", q.Pop())
}