forked from kodecocodes/swift-algorithm-club
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTernarySearchTree.swift
134 lines (111 loc) · 4.17 KB
/
TernarySearchTree.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//
// TernarySearchTree.swift
//
//
// Created by Siddharth Atre on 3/15/16.
//
//
import Foundation
/**
The Ternary Search Tree (TST) Data structure.
Data structure uses key-value mappings. Keys are strings used to map to any data element.
See README for more information.
*/
public class TernarySearchTree<Element> {
/// A reference to the root node of this TST
var root: TSTNode<Element>?
/**
Standard initializer
*/
public init() {}
// MARK: - Insertion
/**
Public insertion method.
- parameter data: The value to store in this TST.
- parameter key: The key to associate with this value.
- returns: Value indicating insertion success/failure.
*/
@discardableResult public func insert(data: Element, withKey key: String) -> Bool {
return insert(node: &root, withData: data, andKey: key, atIndex: 0)
}
/**
Helper method for insertion that does the actual legwork. Insertion is performed recursively.
- parameter node: The current node to insert below.
- parameter data: The data being inserted.
- parameter key: The key being used to find an insertion location for the given data
- parameter charIndex: The index of the character in the key string to use to for the next node.
- returns: Value indicating insertion success/failure.
*/
private func insert(node: inout TSTNode<Element>?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool {
//sanity check.
guard key.characters.count > 0 else {
return false
}
//create a new node if necessary.
if node == nil {
let index = key.index(key.startIndex, offsetBy: charIndex)
node = TSTNode<Element>(key: key[index])
}
//if current char is less than the current node's char, go left
let index = key.index(key.startIndex, offsetBy: charIndex)
if key[index] < node!.key {
return insert(node: &node!.left, withData: data, andKey: key, atIndex: charIndex)
}
//if it's greater, go right.
else if key[index] > node!.key {
return insert(node: &node!.right, withData: data, andKey: key, atIndex: charIndex)
}
//current char is equal to the current nodes, go middle
else {
//continue down the middle.
if charIndex + 1 < key.characters.count {
return insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1)
}
//otherwise, all done.
else {
node!.data = data
node?.hasData = true
return true
}
}
}
// MARK: - Finding
/**
Public find method.
- parameter key: Search for an object associated with this key.
- returns: The element, if found. Otherwise, nil.
*/
public func find(key: String) -> Element? {
return find(node: root, withKey: key, atIndex: 0)
}
/**
Helper method that performs actual legwork of find operation. Implemented recursively.
- parameter node: The current node being evaluated.
- parameter key: The key being used for the search.
- parameter charIndex: The index of the current char in the search key
- returns: The element, if found. Nil otherwise.
*/
private func find(node: TSTNode<Element>?, withKey key: String, atIndex charIndex: Int) -> Element? {
//Given key does not exist in tree.
guard let node = node else {
return nil
}
let index = key.index(key.startIndex, offsetBy: charIndex)
//go left
if key[index] < node.key {
return find(node: node.left, withKey: key, atIndex: charIndex)
}
//go right
else if key[index] > node.key {
return find(node: node.right, withKey: key, atIndex: charIndex)
}
//go middle
else {
if charIndex + 1 < key.characters.count {
return find(node: node.middle, withKey: key, atIndex: charIndex + 1)
} else {
return node.data
}
}
}
}