Swift 如何在固定时间内返回下标?

Swift 如何在固定时间内返回下标?,swift,collections,time-complexity,Swift,Collections,Time Complexity,当符合收集协议时,根据: extension LinkedList: Collection { typealias Index = Int typealias Element = T var startIndex: Index { return 0 } var endIndex: Index { return underestimatedCount } func index(after i: Index)

当符合
收集
协议时,根据:

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))))
符合集合的类型应提供startIndex和endIndex属性,并作为O(1)操作提供对元素的下标访问

如何在固定时间内返回下标?它不需要遍历集合,直到找到正确的索引,然后返回该值吗

这是我用来符合
集合的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
        }
    }
}
间接枚举链接列表{
大小写值(元素:T,下一个:LinkedList)
案例结束
}
扩展链接列表:序列{
func makeIterator()->LinkedListIterator{
返回链接标识符(当前:self)
}
var-dcount:Int{
变量计数=0
为了自己{
计数+=1
}
返回计数
}
}
结构链接标识符:迭代器协议{
当前变量:LinkedList
突变func next()->T{
开关电流{
案例let.value(元素,下一个):
当前=下一个
返回元素
案例.结束:
归零
}
}
}
这就是我实际遵守协议的地方:

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))))
扩展链接列表:集合{
类型别名索引=Int
typealias元素=T
var startIndex:指数{
返回0
}
var endIndex:索引{
返回数据计数
}
func index(在i:index之后)->index{
返回值(i元素{
前提条件(位置=startIndex)
var iterator=makeIterator()
对于处于0..<位置的i{
迭代器
如果i+1==位置{
返回iterator.next()!
}
}
var zero=makeIterator()
返回零。下一步()!
}
}
让test=LinkedList.value(元素:2,下一个:LinkedList.value(元素:4,下一个:LinkedList.value(元素:7,下一个:LinkedList.value(元素:9,下一个:LinkedList.end)))

集合的
索引不必是
Int
。一种可能的方法 是使用一个自定义索引类型,该类型引用了相应的 元素。但是,这要求列表节点是类的实例

这是我想出来的。可能还可以改进,, 但希望能证明这一点

类列表节点
存储 元素和指向下一个节点的指针,以及 整数
序数
,用于生成
结构列表索引
采用
可比的
协议

struct ListIndex
包含对列表节点的引用,或
nil
对于
endIndex

struct LinkedListCollection<T>: Collection {

    class ListNode {
        let element: T
        let next: ListNode?
        let ordinal: Int

        init(element: T, next: ListNode?, ordinal: Int) {
            self.element = element
            self.next = next
            self.ordinal = ordinal
        }

        // Create ListNode as the head of a linked list with elements from an iterator.
        convenience init?<I: IteratorProtocol>(it: inout I, ordinal: Int = 0) where I.Element == T {
            if let el = it.next() {
                self.init(element: el, next: ListNode(it: &it, ordinal: ordinal + 1), ordinal: ordinal)
            } else {
                return nil
            }
        }
    }

    struct ListIndex: Comparable {
        let node: ListNode?

        static func <(lhs: ListIndex, rhs: ListIndex) -> Bool {
            // Compare indices according to the ordinal of the referenced
            // node. `nil` (corresponding to `endIndex`) is ordered last.

            switch (lhs.node?.ordinal, rhs.node?.ordinal) {
            case let (r?, l?):
                return r < l
            case (_?, nil):
                return true
            default:
                return false
            }
        }

        static func ==(lhs: ListIndex, rhs: ListIndex) -> Bool {
            return lhs.node?.ordinal == rhs.node?.ordinal
        }
    }

    let startIndex: ListIndex
    let endIndex: ListIndex

    // Create collection as a linked list from the given elements.
    init<S: Sequence>(elements: S) where S.Iterator.Element == T {
        var it = elements.makeIterator()
        startIndex = ListIndex(node: ListNode(it: &it))
        endIndex = ListIndex(node: nil)
    }

    func index(after i: ListIndex) -> ListIndex {
        guard let next = i.node?.next else {
            return endIndex
        }
        return ListIndex(node: next)
    }

    subscript (position: ListIndex) -> T {
        guard let node = position.node else {
            fatalError("index out of bounds")
        }
        return node.element
    }
}

您可以查看一下它是如何在Swift中实现的。有关此主题的更实用、理论性较低的教程,您还可以检查并注意
undersweedCount
也应该是O(1)。
Collection
方法的默认实现假定为O(1)下标,因此如果您使
LinkedList
符合
Collection
,则,你会发现其中有些太慢了。我认为
Collection
s是一些类似数组的东西,它的元素可以随机访问,
LinkedList
对我来说是一个
序列,而不是
集合。@NandiinBao那就是你想的
RandomAccessCollection
;一种集合,可以在固定时间内使其索引偏移,也可以在固定时间内测量两个索引之间的距离。一个
集合
只是一个
序列
,它可以无破坏性地迭代,并且有一个可以下标的索引。通过
n
places对索引进行偏移可以在O(n)时间内完成(但下标预计会有一个O(1)实现)。