Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Data structures 如何在Go中实现队列?_Data Structures_Go_Queue - Fatal编程技术网

Data structures 如何在Go中实现队列?

Data structures 如何在Go中实现队列?,data-structures,go,queue,Data Structures,Go,Queue,当前Go库未提供队列容器。 为了实现一个简单的队列,我使用圆形数组作为底层数据结构。 它遵循TAOCP中提到的算法: Insert Y into queue X: X[R]<-Y; R<-(R+1)%M; if R=F then OVERFLOW. Delete Y from queue X: if F=R then UNDERFLOW; Y<-X[F]; F<-(F+1) % M. F: Front, R: Rear, M: Array length. 在队列X中插入

当前Go库未提供队列容器。 为了实现一个简单的队列,我使用圆形数组作为底层数据结构。 它遵循TAOCP中提到的算法:

Insert Y into queue X: X[R]<-Y; R<-(R+1)%M; if R=F then OVERFLOW.
Delete Y from queue X: if F=R then UNDERFLOW; Y<-X[F]; F<-(F+1) % M.
F: Front, R: Rear, M: Array length.

在队列X中插入Y:X[R]当
排队
失败时,您仍然在增加
p.tail
,因此下次它看起来不会失败——这解释了第一个循环中的单个
错误(第二个循环会把一切都搞糟)。最初的算法是
OVERFLOW
意思是“放弃一切”,而不是“继续前进,就好像什么都没发生一样”;-)


如果您已经检查了故障正在发生,那么您所需要做的就是递减
p.tail
,或者将递增的值放在本地临时值中,并将其移动到
p.tail
,只有在未发生故障的情况下,这可能会更优雅。通过这种方式,失败的
排队
不会将新值排队,但队列本身(没有溢出值)在语义上仍然完好无损,并且对于将来的操作是正确的。

确实没有称为queue的包,但它们都可以或都可以生成良好的队列。另请参见。

我修改了原始实现以创建动态队列。也就是说,当队列填满时,它将分配一个更大的队列,并将所有项目移到上面

package main

import (
    "fmt"
)

type Queue struct {
    len        uint
    head, tail uint
    q          []int
}

func NextPowerOfTwo(v uint) uint {
    if v == 0 {
        return 1
    }
    v--
    v |= v >> 1
    v |= v >> 2
    v |= v >> 4
    v |= v >> 8
    v |= v >> 16
    v++
    return v
}

func NewQueue(n uint) *Queue {
    n = NextPowerOfTwo(n)
    if n < 4 {
        n = 4
    }
    println("create queue of", n)
    return &Queue{n, 0, 0, make([]int, n)}
}

func (p *Queue) Resize() {
    if p.head == (p.tail + 1) % p.len {
        new_len := p.len * 2;
        new_q := make([]int, new_len)
        // currently there are (len - 1) items in the queue
        var i uint
        for i = 0; i < p.len - 1; i++ {
            n, _ := p.Dequeue()
            new_q[i] = n
        }
        p.q = new_q
        p.head, p.tail = 0, p.len - 1
        p.len = new_len
        println("queue resized to ", p.len)
    }
}

func (p *Queue) Enqueue(x int) {
    p.Resize();
    p.q[p.tail] = x
    p.tail = (p.tail + 1) % p.len
}

func (p *Queue) Dequeue() (int, bool) {
    if p.head == p.tail {
        return -1, false
    }
    x := p.q[p.head]
    p.head = (p.head + 1) % p.len
    return x, true
}

func main() {
    q := NewQueue(1)
    for i := 1; i < 13; i++ {
        q.Enqueue(2 * i + 1)
        println("enqueued item ", i)
    }
    println("** queue content **")
    for i := 1; i < 13 + 1; i++ {
        fmt.Println(q.Dequeue())
    }
}
主程序包
进口(
“fmt”
)
类型队列结构{
蓝尤因
头,尾
q[]整数
}
功能下一个两(v单元)单元的功率{
如果v==0{
返回1
}
五--
v |=v>>1
v |=v>>2
v |=v>>4
v |=v>>8
v |=v>>16
五++
返回v
}
func NewQueue(n单元)*队列{
n=下一个功率2(n)
如果n<4{
n=4
}
println(“创建队列”,n)
返回和队列{n,0,0,make([]int,n)}
}
func(p*队列)调整大小(){
如果p.head==(p.tail+1)%p.len{
新透镜:=p.len*2;
新建q:=make([]整型,新建)
//当前队列中有(len-1)个项目
变量单位
对于i=0;i
缓冲通道产生精细队列,尽管它在创建时有一个固定的最大队列长度。通道具有一个有用的属性,即出列是线程安全的(您的代码不是)。

在任何合理的go版本(1.x之后)中,您都不需要所有这些拥挤。任何事情都可以通过以下方式实现

队列:=[]int{}

添加到队列:

el := queue[0]
queue = queue[1:]
queue=append(队列,6)

从队列中弹出:

el := queue[0]
queue = queue[1:]

这是一个实现,它表明pop不会占用很多时间(事实上,在这里它比push要短,因为在我看来,队列增长时会重新分配内存)

来自@DaveC的评论:

这很简单,适用于除关键代码之外的所有代码 其中分配(垃圾收集器上的压力)是 不受欢迎。有两件事需要注意,首先,它确实不断地重新分配 推送时的底层阵列(虽然效率很高,但并非每次调用都如此) 在这之前,爸爸不会释放任何空间。这导致了 第二件事,如果队列包含指向 某事,那么最好执行队列[0]=nil;队列=队列[1:]到 让队列立即停止引用指针


向量可能不太好,因为从一开始插入或移除东西需要移动所有元素,这非常糟糕inefficient@newacct谢谢,你完全正确。在这种情况下,list肯定会更好,但vector仍然可以在不修改的情况下工作——只是效率不高。现在您不需要这些:
el := queue[0]
queue = queue[1:]
package main

import (
    "fmt"
    "time"
)

func main() {
    n := 10000000
    queue := []int{1, 2, 3}

    start := time.Now()
    for i := 0; i < n; i++ {
        queue = append(queue, i)
    }
    elapsed := time.Since(start)
    fmt.Println(elapsed)

    start = time.Now()
    for i := 0; i < n; i++ {
        _ = queue[0]
        queue = queue[1:]
    }
    elapsed = time.Since(start)
    fmt.Println(elapsed)
    fmt.Println(queue)
}
216.611664ms
13.441106ms