class EnglishDictionary {
private var words: [String]
func words(matching perfix: String) -> [String] {
words.filter { $0.hasPrefix(prefix)}
}
}
public class TrieNode<Key: Hashable> {
public var key: Key?
public weak var parent: TrieNode?
public var children: [Key: TrieNode] = [:]
public var isTerminating = false
public init(key: Key?, parent: TrieNode?) {
self.key = key
self.parent = parent
}
}
- 각 TrieNode가 가지는 데이터로서, 문자열의 각 문자 혹은 다른 타입을 가질 수 있습니다.
- 각 TrieNode가 부모 노드와의 연결을 갖는 weak 참조입니다. 이 연결은 나중에 remove 메서드에서 활용 됩니다.
- TrieNode는 하나 이상의 자식 노드를 가지기 때문에, Dictionary 타입의 children 속성을 이용하여 다수의 자식 노드를 저장합니다.
- 단어의 끝을 나타내는 변수입니다.
public class Trie<CollectionType: Collection> where CollectionType.Element: Hashable {
public typealias Node = TrieNode<CollectionType.Element>
private let root = Node(key: nil, parent: nil)
public init() { }
}
public func insert(_ collection: CollectionType) {
var current = root
for element in collection {
if current.children[element] == nil {
current.children[element] = Node(key: element, parent: current)
}
current = current.children[element]!
}
current.isTerminating = true
}
public func contains(_ collection: CollectionType) -> Bool {
var current = root
for element in collection {
guard let child = current.children[element] else {
return false
}
current = child
}
return current.isTerminating
}
public func remove(_ collection: CollectionType) {
var current = root
for element in colleciton {
guard let child = current.children[element] else {
return
}
current = child
}
guard current.isTerminating else {
return
}
current.isTerminating = false
while let parent = current.parent, current.children.isEmpty && !current.isTerminating {
parent.children[current.key!] = nil
current = parent
}
}
public extension Trie where CollectionType: RangeReplaceableCollection {
func collections(staringWith prefix: CollectionType) -> [CollectionType] {
var current = root
for element in prefix {
guard let child = current.children[element] else {
return []
}
current = child
}
return collections(startingWith: prefix, after: current)
}
RangeReplaceableCollection
를 채택한 extension
내부에 존재해야 합니다. RangeReplaceableCollection
타입의 append
메서드에 접근할 필요가 있기 때문입니다. collections(startingWith: after:)
를 호출합니다. private func collections(startingWith prefix: CollectionType, after node: Node) -> [CollectionType] {
var results: [CollectionType] = []
if node.isTerminating {
results.append(prefix)
}
for child in node.children.values {
var prefix = prefix
prefix.append(child.key!)
reuslts.append(contentsOf: collections(startingWith: prefix, after: child))
}
return results
}
}
collections(startingWith: after:)
를 호출합니다. collections(staringWith:)
의 시간 복잡도는 O(km) 입니다. 여기서 K는 접두사와 일치하는 가장 긴 컬렉션을 나타내고 m은 접두사와 일치하는 컬렉션의 수를 나타냅니다. let trie = Trie<String>()
trie.insert("cute")
trie.insert("cuddd")
print(trie.collections(startingWith: "cud"))
["cuddd"]
제가 학습한 내용을 요약하여 정리한 것입니다. 내용에 오류가 있을 수 있으며, 어떠한 피드백도 감사히 받겠습니다.
감사합니다