在String
3.0中使用index
访问swift
的复杂性是多少?
复杂性是否与数组访问或O(N)或其他东西相同?
来自“字符串索引”下的documentation:
let greeting = "Guten Tag!"
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
.
.
.
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n T a g ! "
如果索引访问是O(N),那么最后一个例子(迭代字符)会非常糟糕,因为只需迭代字符就行O(n ^ 2)
我不确定的原因是以下声明:“不同的字符[...]可能需要不同数量的内存来存储”。
如果复杂性不是O(n),那么它是如何工作的,因为人们不能将偏移量乘以常数来得到内存中的字符?
答案 0 :(得分:3)
除非另有说明,否则Collection
的{{3}}要求的实现总是具有O(1)时间复杂度。这是与Collection
本身签订合同的一部分。
正如subscript
所述(强调我的):
符合
Collection
的类型应提供startIndex
和endIndex
属性和下标对元素的访问权限,作为O(1)操作。无法保证预期性能的类型必须记录出发[...]
当你来到推进指数时会发生潜在的昂贵部分,例如使用the documentation。对于RandomAccessCollection
,其复杂度为O(1),否则为O(n),其中n是偏移量的大小。
index(_:offsetBy:)
不是RandomAccessCollection
,因此推进指数是O(n)。如你所说,原因是字符可以有不同的字节长度。但是一旦你有索引(String.CharacterView
只是字符串的unicode标量的偏移值以及UTF-16代码单元中给定的扩展字形集群的长度),你可以在恒定时间下标。
因此
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: "")
}
是O(n)。循环的每次迭代只是将当前索引提前1,并且下标使用索引的偏移量跳转到扩展字形集群的开头,从而获得该给定索引的字符。
但是,如果我们说:
for offset in 0..<greeting.characters.count {
let index = greeting.index(greeting.startIndex, offsetBy: offset)
print("\(greeting[index]) ", terminator: "")
}
那个将是O(n 2 ),因为我们现在正在循环的每次迭代中从起始索引推进索引(更不用说做一个O(n)步行只是为了得到count
开头的字符。)