Go `附加`复杂性

Go `附加`复杂性,go,Go,在Go编程语言中,这个循环的计算复杂度是多少 var a []int for i := 0 ; i < n ; i++ { a = append(a, i) } var a[]int 对于i:=0;i

在Go编程语言中,这个循环的计算复杂度是多少

var a []int
for i := 0 ; i < n ; i++ {
  a = append(a, i)
}
var a[]int
对于i:=0;i

append
是在线性时间(重新分配内存并在每次追加时复制所有内容)还是在摊销的固定时间(就像许多语言中向量类的实现方式一样)?

它不会在每次追加时重新分配,并且在:

如果s的容量不够大,无法容纳附加值,append将分配一个新的、足够大的切片,以容纳现有切片元素和附加值。因此,返回的片可能引用不同的底层数组

因此,摊销常数时间就是所问的复杂性。

表示,
append
内置函数会在必要时重新分配

如果s的容量不足以容纳附加值, append分配一个新的、足够大的切片,该切片适合 现有切片元素和附加值。因此,该国返回 切片可能引用不同的底层数组

必要时,为追加增加目标切片的精确算法取决于实现。对于当前的
gc
编译器算法,请参阅Go
runtime
包源文件中的
growsice
函数。它是按固定时间摊销的

在某种程度上,切片计算的增长量如下:

    newcap := old.cap
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if old.len < 1024 {
            newcap = doublecap
        } else {
            for newcap < cap {
                newcap += newcap / 4
            }
        }
}
输出:

总承包商:

gccgo:

data     3 3 [0 1 2] 2 2 [3 4]
append   8195 9152 2
constant 8195 9152 2
variable 8195 8195 2
总之,根据实现情况,一旦初始容量被填满,
append
内置函数可能会也可能不会在每次调用时重新分配

参考资料:

如果s的容量不足以容纳附加值,
append
分配一个新的、足够大的切片,该切片适合 现有切片元素和附加值。因此,该国返回 切片可能引用不同的底层数组

规范(见tip和1.0.3)规定:

“如果s的容量不足以容纳额外的 值,
append
分配一个新的、足够大的、适合 现有的slice元素和附加值 返回的切片可能引用不同的基础数组。“

这应该是“如果且仅当”吗?例如,如果我知道 我的切片容量足够长,我能保证吗 是否不更改基础数组

是的,你很放心

运行时源文件


这并不是说“它不会在每个附加上重新分配”。它只是说,如果必要,它会重新分配。@peterSO:Rob Pike,语言作者之一,请求不同意见:不,他没有。我在我的回答中添加了一个附录。@peterSO:“是的,你很有把握。”中的哪个词没有清楚地传达Rob对[邮件列表]OP问题的回答?(这是:“例如,如果我知道我的片的容量足够长,我是否可以保证我不会更改底层数组?”;-)@zzzz,这只是在讨论现有切片足够大的情况。Rob(在这段引文中)完全没有提到在不这样的情况下可以分配多少空间。如果它只是与需要的一样多,那么重新分配就不会被摊销。是的,尽管语言或库引用最好指定它的复杂性,所以用户在编写大型应用程序时可以依赖复杂性。
data     3 3 [0 1 2] 2 2 [3 4]
append   8195 9152 2
constant 8195 9152 2
variable 8195 8195 2
data     3 3 [0 1 2] 2 2 [3 4]
append   8195 9152 2
constant 8195 9152 2
variable 8195 8195 2