Skip to content

Commit 0d7a81f

Browse files
author
Chris Pilcher
committed
Merge pull request kodecocodes#82 from Satre95/TernarySearchTree
Ternary search tree
2 parents 475d23c + 636fd45 commit 0d7a81f

File tree

8 files changed

+402
-0
lines changed

8 files changed

+402
-0
lines changed

Ternary Search Tree/README.markdown

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Ternary Search Tree
2+
3+
Data structure and simple test in playground has been implemented.
4+
Documentation and examples coming soon!! :)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//: Playground - noun: a place where people can play
2+
3+
import Cocoa
4+
import Foundation
5+
6+
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+
}
23+
24+
var testStrings: [(key:String, data:String)] = []
25+
let testCount = 30
26+
for _ in (1...testCount) {
27+
let randomLength = Int(arc4random_uniform(10))
28+
let key = randomAlphaNumericString(randomLength)
29+
let data = randomAlphaNumericString(randomLength)
30+
// print("Key: \(key) Data: \(data)")
31+
32+
if key != "" && data != "" {
33+
testStrings.append((key, data))
34+
treeOfStrings.insert(data, withKey: key)
35+
}
36+
}
37+
38+
for aTest in testStrings {
39+
let data = treeOfStrings.find(aTest.key)
40+
41+
if data == nil {
42+
print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)")
43+
}
44+
if data != aTest.data {
45+
print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)")
46+
}
47+
}
48+
49+
var testNums: [(key: String, data: Int)] = []
50+
let treeOfInts = TernarySearchTree<Int>()
51+
for _ in (1...testCount) {
52+
let randomNum = Int(arc4random_uniform(UInt32.max))
53+
let randomLength = Int(arc4random_uniform(10))
54+
let key = randomAlphaNumericString(randomLength)
55+
56+
if key != "" {
57+
testNums.append((key, randomNum))
58+
treeOfInts.insert(randomNum, withKey: key)
59+
}
60+
}
61+
62+
for aTest in testNums {
63+
let data = treeOfInts.find(aTest.key)
64+
if data == nil {
65+
print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)")
66+
}
67+
if data != aTest.data {
68+
print("TEST FAILED. Key: \(aTest.key) Data: \(aTest.data)")
69+
}
70+
}
71+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// TSTNode.swift
3+
//
4+
//
5+
// Created by Siddharth Atre on 3/15/16.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
class TSTNode<Element> {
12+
//Member properties of a particular node.
13+
var key: Character
14+
var data: Element?
15+
var hasData: Bool
16+
17+
//Children
18+
var left: TSTNode?, right: TSTNode?, middle: TSTNode?
19+
20+
21+
init(key: Character, data: Element?) {
22+
self.key = key
23+
self.data = data
24+
self.hasData = (data != nil)
25+
}
26+
27+
init(key:Character) {
28+
self.key = key
29+
self.data = nil
30+
self.hasData = false
31+
}
32+
33+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//
2+
// TernarySearchTree.swift
3+
//
4+
//
5+
// Created by Siddharth Atre on 3/15/16.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
12+
public class TernarySearchTree<Element> {
13+
14+
var root: TSTNode<Element>?
15+
16+
public init() {}
17+
18+
//MARK: - Insertion
19+
20+
public func insert(data:Element, withKey key: String) -> Bool{
21+
return insertNode(&root, withData: data, andKey: key, atIndex: 0)
22+
23+
}
24+
25+
private func insertNode(inout aNode: TSTNode<Element>?, withData data: Element, andKey key: String, atIndex charIndex: Int) -> Bool {
26+
27+
//sanity check.
28+
if(key.characters.count == 0) {
29+
return false
30+
}
31+
32+
//create a new node if necessary.
33+
if(aNode == nil) {
34+
let index = key.startIndex.advancedBy(charIndex)
35+
aNode = TSTNode<Element>(key: key[index])
36+
}
37+
38+
//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)
42+
}
43+
//if it's greater, go right.
44+
else if(key[index] > aNode!.key) {
45+
return insertNode(&aNode!.right, withData: data, andKey: key, atIndex: charIndex)
46+
}
47+
//current char is equal to the current nodes, go middle
48+
else {
49+
//continue down the middle.
50+
if(charIndex + 1 < key.characters.count) {
51+
return insertNode(&aNode!.middle, withData: data, andKey: key, atIndex: charIndex + 1)
52+
}
53+
//otherwise, all done.
54+
else {
55+
aNode!.data = data
56+
aNode?.hasData = true
57+
return true
58+
}
59+
}
60+
}
61+
62+
63+
//MARK: - Finding
64+
65+
66+
public func find(key:String) -> Element? {
67+
return findNode(root, withKey: key, atIndex: 0)
68+
}
69+
70+
71+
private func findNode(aNode: TSTNode<Element>?, withKey key: String, atIndex charIndex: Int) -> Element? {
72+
73+
//Given key does not exist in tree.
74+
if aNode == nil {
75+
return nil
76+
}
77+
78+
let index = key.startIndex.advancedBy(charIndex)
79+
//go left
80+
if key[index] < aNode!.key {
81+
return findNode(aNode!.left, withKey: key, atIndex: charIndex)
82+
}
83+
//go right
84+
else if key[index] > aNode!.key {
85+
return findNode(aNode!.right, withKey: key, atIndex: charIndex)
86+
}
87+
//go middle
88+
else {
89+
if charIndex + 1 < key.characters.count {
90+
return findNode(aNode!.middle, withKey: key, atIndex: charIndex + 1)
91+
} else {
92+
return aNode!.data
93+
}
94+
}
95+
}
96+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='osx'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>

Ternary Search Tree/TSTNode.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// TSTNode.swift
3+
//
4+
//
5+
// Created by Siddharth Atre on 3/15/16.
6+
//
7+
//
8+
9+
import Foundation
10+
11+
/**
12+
This class represents a node in the Ternary Search Tree.
13+
A node has two main data members, the key and the data.
14+
All nodes in a TST must have keys, but only some will have data.
15+
This can be seen in the way the data variable is of Optional type.
16+
*/
17+
class TSTNode<Element> {
18+
//Member properties of a particular node.
19+
20+
/// The key that identifies this node.
21+
var key: Character
22+
/// The data stored in this node. May be `nil`
23+
var data: Element?
24+
/// Boolean flag to depict whether this node holds data or not.
25+
var hasData: Bool
26+
27+
/// The children of this node
28+
var left: TSTNode?, right: TSTNode?, middle: TSTNode?
29+
30+
/**
31+
Initializer for key and/or data
32+
33+
- parameter key: The key to set for this node.
34+
- parameter data: The optional data to set in this node.
35+
*/
36+
init(key: Character, data: Element?) {
37+
self.key = key
38+
self.data = data
39+
self.hasData = (data != nil)
40+
}
41+
42+
/**
43+
Make a node that only has a key
44+
45+
- parameter key: The key to ascribe to this node.
46+
*/
47+
init(key:Character) {
48+
self.key = key
49+
self.data = nil
50+
self.hasData = false
51+
}
52+
53+
}

0 commit comments

Comments
 (0)