字典樹(Trie)-Swift實現

若是你谷歌「cool data structures」,你搜索到的第一個結果就會是這個內容。這是一個stackoverflow問題:「有哪些數據結構比較少人知道,可是頗有用?」,點贊最多的第一條答案就是字典樹。我仔細研究了這些關於字典樹答案,在其應用方面發現了一些有趣的事情(也發現我本身也是這種谷歌「cool data structures」的那種人),因此,我來到xcode playground,寫下這些代碼。xcode

字典樹就是前綴樹,是一種遞歸數據結構:每一個字典樹都包含其餘的子樹,能夠經過前綴來識別。數據結構

這是一種比較時髦的數據結構,並無被普遍的應用,可是確有一些很是實用的應用。它有相似集合的操做,包括插入和搜索操做時間複雜度在O(n),其中n是搜索序列的長度。集合是可hash的無序元素的惟一方式,可是,針對有序的hash元素序列,字典樹或許更適合你。(有一件事須要告訴你,就是集合可以針對元素自身hash,因此,若是你想存儲的序列是無序的,一個元素是集合的集合是更適合的。)less

trie

A trie for keys 「A」, 「to」, 「tea」, 「ted」, 「ten」, 「i」, 「in」, and 「inn」.函數

在Swift裏面,咱們可以使每個字典樹包含一個字典,字典包含前綴和字典樹。相似這樣:spa

public struct Trie<Element : Hashable> {
    private var children: [Element:Trie<Element>]
}
複製代碼

咱們不會遇到結構體不能遞歸的狀況,由於咱們不直接存儲一個字典樹在一個字典樹裏面——咱們存儲的是一個字典,而且會關聯到子字典樹,在這個字典裏面,前綴是這個字典的鍵值。因此,怎麼補充接下來的內容呢(初始化)?咱們能夠像列表生成器同樣分解屬性:code

extension Trie {
    private init<G : GeneratorType where G.Element == Element>(var gen: G) {
        if let head = gen.next() {
            children = [head: Trie(gen: gen)]
        } else {
            children = [:]
        }
    }
    public init<S : SequenceType where S.Generator.Element == Element>(_ seq: S) {
        self.init(gen: seq.generator())
    }
}
複製代碼

這還不夠,想要存儲一個序列,咱們還要一個insert函數,方法以下:cdn

extension Trie {
    private mutating func insert<G : GeneratorType where G.Element = Element>(var gen: G) {
        if let head = gen.next() {
            children[head]?.insert(gen) ?? {children[head] == Trie(gen: gen)}()
        }
    }
    public mutating func insert<S : SequenceType where S.Generator.Element == Element>(_ seq: S) {
        insert(seq.generate())
    }
}
複製代碼
相關文章
相關標籤/搜索