Skip to content

Commit 53b8771

Browse files
pbodskvincentngo
authored andcommitted
Migrates Ternary Search Tree to Swift 3 syntax (kodecocodes#352)
* migrates Ternary Search Tree to Swift 3 syntax * aligning function names as suggested * adds unit tests to TernarySearchTree * adds guards as suggested
1 parent 6ec92d7 commit 53b8771

File tree

12 files changed

+529
-76
lines changed

12 files changed

+529
-76
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ script:
4343
- xcodebuild test -project ./Topological\ Sort/Tests/Tests.xcodeproj -scheme Tests
4444
- xcodebuild test -project ./Treap/Treap/Treap.xcodeproj -scheme Tests
4545
- xcodebuild test -project ./Palindromes/Test/Test.xcodeproj -scheme Test
46+
- xcodebuild test -project ./Ternary\ Search\ Tree/Tests/Tests.xcodeproj -scheme Tests

Ternary Search Tree/TST.playground/Contents.swift

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,23 @@ import Cocoa
44
import Foundation
55

66
let treeOfStrings = TernarySearchTree<String>()
7-
let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
8-
9-
//Random string generator from:
10-
//http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710
11-
func randomAlphaNumericString(length: Int) -> String {
12-
let allowedCharsCount = UInt32(allowedChars.characters.count)
13-
var randomString = ""
14-
15-
for _ in (0..<length) {
16-
let randomNum = Int(arc4random_uniform(allowedCharsCount))
17-
let newCharacter = allowedChars[allowedChars.startIndex.advancedBy(randomNum)]
18-
randomString += String(newCharacter)
19-
}
20-
21-
return randomString
22-
}
237

248
var testStrings: [(key: String, data: String)] = []
259
let testCount = 30
2610
for _ in (1...testCount) {
2711
let randomLength = Int(arc4random_uniform(10))
28-
let key = randomAlphaNumericString(randomLength)
29-
let data = randomAlphaNumericString(randomLength)
12+
let key = Utils.shared.randomAlphaNumericString(withLength: randomLength)
13+
let data = Utils.shared.randomAlphaNumericString(withLength: randomLength)
3014
// print("Key: \(key) Data: \(data)")
3115

3216
if key != "" && data != "" {
3317
testStrings.append((key, data))
34-
treeOfStrings.insert(data, withKey: key)
18+
treeOfStrings.insert(data: data, withKey: key)
3519
}
3620
}
3721

3822
for aTest in testStrings {
39-
let data = treeOfStrings.find(aTest.key)
23+
let data = treeOfStrings.find(key: aTest.key)
4024

4125
if data == nil {
4226
print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)")
@@ -51,16 +35,16 @@ let treeOfInts = TernarySearchTree<Int>()
5135
for _ in (1...testCount) {
5236
let randomNum = Int(arc4random_uniform(UInt32.max))
5337
let randomLength = Int(arc4random_uniform(10))
54-
let key = randomAlphaNumericString(randomLength)
38+
let key = Utils.shared.randomAlphaNumericString(withLength: randomLength)
5539

5640
if key != "" {
5741
testNums.append((key, randomNum))
58-
treeOfInts.insert(randomNum, withKey: key)
42+
treeOfInts.insert(data: randomNum, withKey: key)
5943
}
6044
}
6145

6246
for aTest in testNums {
63-
let data = treeOfInts.find(aTest.key)
47+
let data = treeOfInts.find(key: aTest.key)
6448
if data == nil {
6549
print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)")
6650
}

Ternary Search Tree/TST.playground/Sources/TernarySearchTree.swift

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,41 @@ public class TernarySearchTree<Element> {
1818
//MARK: - Insertion
1919

2020
public func insert(data: Element, withKey key: String) -> Bool {
21-
return insertNode(&root, withData: data, andKey: key, atIndex: 0)
22-
21+
return insert(node: &root, withData: data, andKey: key, atIndex: 0)
2322
}
2423

25-
private func insertNode(inout aNode: TSTNode<Element>?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool {
24+
private func insert(node: inout TSTNode<Element>?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool {
2625

2726
//sanity check.
2827
if key.characters.count == 0 {
2928
return false
3029
}
3130

3231
//create a new node if necessary.
33-
if aNode == nil {
34-
let index = key.startIndex.advancedBy(charIndex)
35-
aNode = TSTNode<Element>(key: key[index])
32+
if node == nil {
33+
let index = key.index(key.startIndex, offsetBy: charIndex)
34+
node = TSTNode<Element>(key: key[index])
3635
}
3736

3837
//if current char is less than the current node's char, go left
39-
let index = key.startIndex.advancedBy(charIndex)
40-
if key[index] < aNode!.key {
41-
return insertNode(&aNode!.left, withData: data, andKey: key, atIndex: charIndex)
38+
let index = key.index(key.startIndex, offsetBy: charIndex)
39+
if key[index] < node!.key {
40+
return insert(node: &node!.left, withData: data, andKey: key, atIndex: charIndex)
4241
}
4342
//if it's greater, go right.
44-
else if key[index] > aNode!.key {
45-
return insertNode(&aNode!.right, withData: data, andKey: key, atIndex: charIndex)
43+
else if key[index] > node!.key {
44+
return insert(node: &node!.right, withData: data, andKey: key, atIndex: charIndex)
4645
}
4746
//current char is equal to the current nodes, go middle
4847
else {
4948
//continue down the middle.
5049
if charIndex + 1 < key.characters.count {
51-
return insertNode(&aNode!.middle, withData: data, andKey: key, atIndex: charIndex + 1)
50+
return insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1)
5251
}
5352
//otherwise, all done.
5453
else {
55-
aNode!.data = data
56-
aNode?.hasData = true
54+
node!.data = data
55+
node?.hasData = true
5756
return true
5857
}
5958
}
@@ -64,32 +63,31 @@ public class TernarySearchTree<Element> {
6463

6564

6665
public func find(key: String) -> Element? {
67-
return findNode(root, withKey: key, atIndex: 0)
66+
return find(node: root, withKey: key, atIndex: 0)
6867
}
6968

70-
71-
private func findNode(aNode: TSTNode<Element>?, withKey key: String, atIndex charIndex: Int) -> Element? {
69+
private func find(node: TSTNode<Element>?, withKey key: String, atIndex charIndex: Int) -> Element? {
7270

7371
//Given key does not exist in tree.
74-
if aNode == nil {
72+
if node == nil {
7573
return nil
7674
}
7775

78-
let index = key.startIndex.advancedBy(charIndex)
76+
let index = key.index(key.startIndex, offsetBy: charIndex)
7977
//go left
80-
if key[index] < aNode!.key {
81-
return findNode(aNode!.left, withKey: key, atIndex: charIndex)
78+
if key[index] < node!.key {
79+
return find(node: node!.left, withKey: key, atIndex: charIndex)
8280
}
8381
//go right
84-
else if key[index] > aNode!.key {
85-
return findNode(aNode!.right, withKey: key, atIndex: charIndex)
82+
else if key[index] > node!.key {
83+
return find(node: node!.right, withKey: key, atIndex: charIndex)
8684
}
8785
//go middle
8886
else {
8987
if charIndex + 1 < key.characters.count {
90-
return findNode(aNode!.middle, withKey: key, atIndex: charIndex + 1)
88+
return find(node: node!.middle, withKey: key, atIndex: charIndex + 1)
9189
} else {
92-
return aNode!.data
90+
return node!.data
9391
}
9492
}
9593
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// Utils.swift
3+
//
4+
//
5+
// Created by Peter Bødskov on 10/01/17.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
public struct Utils {
12+
13+
public static let shared = Utils()
14+
15+
let allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
16+
//Random string generator from:
17+
//http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift/26845710
18+
public func randomAlphaNumericString(withLength length: Int) -> String {
19+
let allowedCharsCount = UInt32(allowedChars.characters.count)
20+
var randomString = ""
21+
22+
for _ in (0..<length) {
23+
let randomNum = Int(arc4random_uniform(allowedCharsCount))
24+
let newCharacter = allowedChars[allowedChars.index(allowedChars.startIndex, offsetBy: randomNum)]
25+
randomString += String(newCharacter)
26+
}
27+
28+
return randomString
29+
}
30+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2-
<playground version='5.0' target-platform='osx'>
2+
<playground version='5.0' target-platform='osx' last-migration='0810'>
33
<timeline fileName='timeline.xctimeline'/>
44
</playground>

Ternary Search Tree/TernarySearchTree.swift

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,52 +33,52 @@ public class TernarySearchTree<Element> {
3333

3434
- returns: Value indicating insertion success/failure.
3535
*/
36-
public func insert(data: Element, withKey key: String) -> Bool {
37-
return insertNode(&root, withData: data, andKey: key, atIndex: 0)
36+
@discardableResult public func insert(data: Element, withKey key: String) -> Bool {
37+
return insert(node: &root, withData: data, andKey: key, atIndex: 0)
3838
}
3939

4040
/**
4141
Helper method for insertion that does the actual legwork. Insertion is performed recursively.
4242

43-
- parameter aNode: The current node to insert below.
43+
- parameter node: The current node to insert below.
4444
- parameter data: The data being inserted.
4545
- parameter key: The key being used to find an insertion location for the given data
4646
- parameter charIndex: The index of the character in the key string to use to for the next node.
4747

4848
- returns: Value indicating insertion success/failure.
4949
*/
50-
private func insertNode(inout aNode: TSTNode<Element>?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool {
50+
private func insert(node: inout TSTNode<Element>?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool {
5151

5252
//sanity check.
53-
if key.characters.count == 0 {
53+
guard key.characters.count > 0 else {
5454
return false
5555
}
5656

5757
//create a new node if necessary.
58-
if aNode == nil {
59-
let index = key.startIndex.advancedBy(charIndex)
60-
aNode = TSTNode<Element>(key: key[index])
58+
if node == nil {
59+
let index = key.index(key.startIndex, offsetBy: charIndex)
60+
node = TSTNode<Element>(key: key[index])
6161
}
6262

6363
//if current char is less than the current node's char, go left
64-
let index = key.startIndex.advancedBy(charIndex)
65-
if key[index] < aNode!.key {
66-
return insertNode(&aNode!.left, withData: data, andKey: key, atIndex: charIndex)
64+
let index = key.index(key.startIndex, offsetBy: charIndex)
65+
if key[index] < node!.key {
66+
return insert(node: &node!.left, withData: data, andKey: key, atIndex: charIndex)
6767
}
6868
//if it's greater, go right.
69-
else if key[index] > aNode!.key {
70-
return insertNode(&aNode!.right, withData: data, andKey: key, atIndex: charIndex)
69+
else if key[index] > node!.key {
70+
return insert(node: &node!.right, withData: data, andKey: key, atIndex: charIndex)
7171
}
7272
//current char is equal to the current nodes, go middle
7373
else {
7474
//continue down the middle.
7575
if charIndex + 1 < key.characters.count {
76-
return insertNode(&aNode!.middle, withData: data, andKey: key, atIndex: charIndex + 1)
76+
return insert(node: &node!.middle, withData: data, andKey: key, atIndex: charIndex + 1)
7777
}
7878
//otherwise, all done.
7979
else {
80-
aNode!.data = data
81-
aNode?.hasData = true
80+
node!.data = data
81+
node?.hasData = true
8282
return true
8383
}
8484
}
@@ -95,40 +95,40 @@ public class TernarySearchTree<Element> {
9595
- returns: The element, if found. Otherwise, nil.
9696
*/
9797
public func find(key: String) -> Element? {
98-
return findNode(root, withKey: key, atIndex: 0)
98+
return find(node: root, withKey: key, atIndex: 0)
9999
}
100100

101101
/**
102102
Helper method that performs actual legwork of find operation. Implemented recursively.
103103

104-
- parameter aNode: The current node being evaluated.
104+
- parameter node: The current node being evaluated.
105105
- parameter key: The key being used for the search.
106106
- parameter charIndex: The index of the current char in the search key
107107

108108
- returns: The element, if found. Nil otherwise.
109109
*/
110-
private func findNode(aNode: TSTNode<Element>?, withKey key: String, atIndex charIndex: Int) -> Element? {
110+
private func find(node: TSTNode<Element>?, withKey key: String, atIndex charIndex: Int) -> Element? {
111111

112112
//Given key does not exist in tree.
113-
if aNode == nil {
113+
guard let node = node else {
114114
return nil
115115
}
116116

117-
let index = key.startIndex.advancedBy(charIndex)
117+
let index = key.index(key.startIndex, offsetBy: charIndex)
118118
//go left
119-
if key[index] < aNode!.key {
120-
return findNode(aNode!.left, withKey: key, atIndex: charIndex)
119+
if key[index] < node.key {
120+
return find(node: node.left, withKey: key, atIndex: charIndex)
121121
}
122122
//go right
123-
else if key[index] > aNode!.key {
124-
return findNode(aNode!.right, withKey: key, atIndex: charIndex)
123+
else if key[index] > node.key {
124+
return find(node: node.right, withKey: key, atIndex: charIndex)
125125
}
126126
//go middle
127127
else {
128128
if charIndex + 1 < key.characters.count {
129-
return findNode(aNode!.middle, withKey: key, atIndex: charIndex + 1)
129+
return find(node: node.middle, withKey: key, atIndex: charIndex + 1)
130130
} else {
131-
return aNode!.data
131+
return node.data
132132
}
133133
}
134134
}

Ternary Search Tree/Tests/Info.plist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>BNDL</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleVersion</key>
20+
<string>1</string>
21+
</dict>
22+
</plist>

0 commit comments

Comments
 (0)