【发布时间】:2018-01-18 19:31:16
【问题描述】:
按照Swift Documentation当符合Collection协议时:
符合 Collection 的类型应提供 startIndex 和 endIndex 属性以及对元素的下标访问作为 O(1) 操作。
如何在恒定时间内返回下标?它不需要遍历集合,直到正确的索引,然后返回该值吗?
这是我用来符合 Collection 的 LinkedList:
indirect enum LinkedList<T> {
case value(element: T, next: LinkedList<T>)
case end
}
extension LinkedList: Sequence {
func makeIterator() -> LinkedListIterator<T> {
return LinkedListIterator(current: self)
}
var underestimatedCount: Int {
var count = 0
for _ in self {
count += 1
}
return count
}
}
struct LinkedListIterator<T>: IteratorProtocol {
var current: LinkedList<T>
mutating func next() -> T? {
switch current {
case let .value(element, next):
current = next
return element
case .end:
return nil
}
}
}
这是我真正遵守协议的地方:
extension LinkedList: Collection {
typealias Index = Int
typealias Element = T
var startIndex: Index {
return 0
}
var endIndex: Index {
return underestimatedCount
}
func index(after i: Index) -> Index {
return (i < endIndex) ? i + 1 : endIndex
}
subscript (position: Index) -> Element {
precondition(position < endIndex && position >= startIndex)
var iterator = makeIterator()
for i in 0 ..< position {
iterator.next()
if i + 1 == position {
return iterator.next()!
}
}
var zero = makeIterator()
return zero.next()!
}
}
let test = LinkedList<Int>.value(element: 2, next: LinkedList<Int>.value(element: 4, next: LinkedList<Int>.value(element: 7, next: LinkedList<Int>.value(element: 9, next: LinkedList<Int>.end))))
【问题讨论】:
-
您可以查看Collection's source code 以了解它是如何在 Swift 本身中实现的。有关该主题的更实用,更少理论的教程,您还可以查看this tutorial by raywenderlich
-
请注意,
underestimatedCount也应该是 O(1)。 -
Collection方法的默认实现是假设 O(1) 下标,所以如果你让你的LinkedList符合Collection,你会发现其中一些太慢了。跨度> -
我认为
Collections 类似于数组,其元素可以随机访问,而LinkedList对我来说是Sequence而不是Collection。 -
@NandiinBao 你想的是
RandomAccessCollection;一个集合,它的索引可以在恒定时间内偏移,以及在恒定时间内测量两个索引之间的距离。Collection只是一个Sequence可以非破坏性地迭代,并且有一个可以下标的索引。将索引偏移n个位置可以在 O(n) 时间内发生(但 subscript 预计会有 O(1) 实现)。
标签: swift collections time-complexity