- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
Go 编程语言中这个循环的计算复杂度是多少?
var a []int
for i := 0 ; i < n ; i++ {
a = append(a, i)
}
append
是按线性时间运行(重新分配内存并在每次附加时复制所有内容)还是按摊销常数时间运行(就像许多语言中向量类的实现方式)?
最佳答案
The Go Programming Language Specification表示 append
内置函数会在必要时重新分配。
Appending to and copying slices
If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large slice that fits both the existing slice elements and the additional values. Thus, the returned slice may refer to a different underlying array.
在必要时为追加增长目标 slice 的精确算法取决于实现。对于当前的gc
编译器算法,请参见Go runtime
包中的growslice
函数slice.go
源文件。它是摊销的常数时间。
部分增长量 slice 计算如下:
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
}
}
}
附录
Go Programming Language Specification允许语言的实现者以多种方式实现 append
内置函数。
例如,新分配只需“足够大”。分配的数量可以是 parsimonius,分配最小必要的量,也可以是慷慨的,分配超过最小必要量以最小化多次调整大小的成本。 Go gc
编译器使用了一个慷慨的动态数组摊销常数时间算法。
以下代码说明了 append
内置函数的两种合法实现。慷慨的常量函数实现了与 Go gc
编译器相同的分摊常量时间算法。 parsimonius 变量函数,一旦初始分配被填满,每次都会重新分配和复制所有内容。 Go append
函数和 Go gccgo
编译器用作控件。
package main
import "fmt"
// Generous reallocation
func constant(s []int, x ...int) []int {
if len(s)+len(x) > cap(s) {
newcap := len(s) + len(x)
m := cap(s)
if m+m < newcap {
m = newcap
} else {
for {
if len(s) < 1024 {
m += m
} else {
m += m / 4
}
if !(m < newcap) {
break
}
}
}
tmp := make([]int, len(s), m)
copy(tmp, s)
s = tmp
}
if len(s)+len(x) > cap(s) {
panic("unreachable")
}
return append(s, x...)
}
// Parsimonious reallocation
func variable(s []int, x ...int) []int {
if len(s)+len(x) > cap(s) {
tmp := make([]int, len(s), len(s)+len(x))
copy(tmp, s)
s = tmp
}
if len(s)+len(x) > cap(s) {
panic("unreachable")
}
return append(s, x...)
}
func main() {
s := []int{0, 1, 2}
x := []int{3, 4}
fmt.Println("data ", len(s), cap(s), s, len(x), cap(x), x)
a, c, v := s, s, s
for i := 0; i < 4096; i++ {
a = append(a, x...)
c = constant(c, x...)
v = variable(v, x...)
}
fmt.Println("append ", len(a), cap(a), len(x))
fmt.Println("constant", len(c), cap(c), len(x))
fmt.Println("variable", len(v), cap(v), len(x))
}
输出:
gc:
data 3 3 [0 1 2] 2 2 [3 4]
append 8195 9152 2
constant 8195 9152 2
variable 8195 8195 2
gccgo:
data 3 3 [0 1 2] 2 2 [3 4]
append 8195 9152 2
constant 8195 9152 2
variable 8195 8195 2
总而言之,根据实现,一旦初始容量被填满,append
内置函数可能会或可能不会在每次调用时重新分配。
引用资料:
Appending to and copying slices
If the capacity of s is not large enough to fit the additional values,
append
allocates a new, sufficiently large slice that fits both the existing slice elements and the additional values. Thus, the returned slice may refer to a different underlying array.Append to a slice specification discussion
The spec (at tip and 1.0.3) states:
"If the capacity of s is not large enough to fit the additional values,
append
allocates a new, sufficiently large slice that fits both the existing slice elements and the additional values. Thus, the returned slice may refer to a different underlying array."Should this be an "If and only if"? For example, if I know the capacity of my slice is sufficiently long, am I assured that I will not change the underlying array?
Yes you are so assured.
运行时 slice.go源文件
关于go - `append` 复杂度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15702419/
Racket 的 pict , 有几个 combinators for combining other pictures .这些文档包含一个很好的表格,说明其 *-append 组合器的工作方式: 这
我看过 Insert content into iFrame和他们的 fiddle http://jsfiddle.net/8VP4y/3/提出以下我遇到问题的代码。 我已经为下面的问题创建了一个 j
我有一个显示非常奇怪结果的微基准: @BenchmarkMode(Mode.Throughput) @Fork(1) @State(Scope.Thread) @Warmup(iterations =
我想知道是否有人可以回答我使用 StringBuilder 对象在 java 中执行这些语句中的哪一个会更好: 使用 .append(string1 + string 2) 对比 .append(st
假设我有两个相同类型的流。是否可以将一个流 append 到另一个流而无需事先将它们转换为列表? 例子: Stream ms = ...; Stream ns = ...; return ms.app
我有以下有效的 jQuery 代码,但它让我思考是否可以对正在 append 的内容执行 append 操作,而无需指定我想要 append 的内容。 append().append() 并没有达到目
这是为了显示诊断页面的检查。我有一个 .append(not_ok) 但当 swf 文件加载 100% 时,我想删除 not_ok 附加,然后添加一个 .append(ok)。 function ca
x = [[1,2],[2,3],[10,1],[10,10]] def duplicatingRows(x, l): severity = x[l][1] if severity =
我有一个列表,我正在尝试将数据注入(inject)其中。列表如下所示 data2 = ['TECH2_HELP', 'TECH2_1507', 'TECH2_1189', 'TECH2_4081',
为了有效地进行一些 DOM 操作,我分离了一个元素。在这个过程中,我遇到了一个有趣的情况: var $holder = $("#d"); var $wrapper = $("").css("borde
我遇到了图片在移动设备上加载速度不够快的问题。我的元素有一个图像和一个按钮。单击该按钮时,图像向下滑动,另一幅图像从顶部滑动以取代它。这是代码 html CSS .moveF
我正在编写一个包含 10 个遗愿 list 的简单哈希表。使用内置的 hash() 计算索引,然后对表大小取模。但是,当我尝试将该对象 append 到该索引处的存储桶列表时,它会 append 到每
我是 LISP 的新手,我正在尝试处理类的 cond 语句。目前,我正在尝试检查传递的值是否为列表,如果是,则将字母 d append 到列表中。 这是我的代码: (defun test(L) (li
我正在使用 Jquery 将数据 append 到 div。但是,append 语句之后页面上没有显示任何内容。 我尝试使用 $(window).load 来确保页面已加载,但这仍然不起作用。 HTM
我有以下代码; function SetupDropdowns() { var PrevType; dropdown1 = document.getElemen
我想在 smarty 中创建一个数组并在其中执行 append 功能!就像我在 smarty 模板中声明一个变量(如 {assign var=sizearr value=''} )然后我想在循环中向其
请考虑以下代码片段: var ul = $(".list_b").find("li").remove().end(); $.each(Sites, functi
我的日志记录配置中有两个 appenders。其中之一在 ERROR 事件上发送电子邮件。 一个类,我无法控制,垃圾邮件 ERROR 消息。所以我仍然想要那些消息,但不是在两个 appenders 中
我正在尝试制作 editText,我要在其中插入一些文本。在每三个字符之后,我想插入破折号。 例子: 类型:123 结果:123- 现在当光标在破折号后面并且你按下删除键时,我想删除破折号和破折号
当我尝试 append 简单的“hello”时,它会被 append ,但很快就会自动删除。仅当我在下面给出的表单中使用它时,才会出现此问题,如果删除该表单,则不会出现问题,并且 hello 会正确
我是一名优秀的程序员,十分优秀!