Skip to content

Commit 11d7e8a

Browse files
committed
Testing two approaches to a RadixTree
1 parent 2e16592 commit 11d7e8a

File tree

2 files changed

+272
-0
lines changed

2 files changed

+272
-0
lines changed

Radix-Tree/EdgeTree.swift

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
class Root {
2+
3+
var children: [Edge]
4+
5+
init() {
6+
children = [Edge]()
7+
}
8+
9+
}
10+
11+
class Edge: Root {
12+
13+
var parent: Edge?
14+
var label: String
15+
16+
init(_ label: String) {
17+
self.label = label
18+
super.init()
19+
}
20+
21+
}
22+
23+
class EdgeTree {
24+
25+
var root: Root
26+
27+
init() {
28+
root = Root()
29+
}
30+
31+
func insert(_ str: String) -> Bool {
32+
33+
//Account for a blank input
34+
if str == "" {
35+
return true
36+
}
37+
38+
//Account for an empty tree
39+
if root.children.count == 0 {
40+
root.children.append( Edge(str) )
41+
return true
42+
}
43+
44+
var searchStr = str
45+
var currEdge = root
46+
47+
while (true) {
48+
49+
var i = 0
50+
51+
for e in currEdge.children {
52+
53+
//Get the shared
54+
var shared = sharedPrefix(searchStr, e.label)
55+
var index = shared.startIndex
56+
57+
//The search string is equal to the shared string
58+
//so the string already exists in the tree
59+
if searchStr == shared {
60+
return false
61+
}
62+
63+
//The child's label is a prefix of the search string
64+
else if e.label.hasPrefix(shared) {
65+
66+
for _ in 1...shared.characters.count {
67+
index = index.successor()
68+
}
69+
70+
//Substring the search string so that the prefix is removed
71+
searchStr = searchStr.substringFromIndex(index)
72+
73+
//Set currNode to e
74+
currEdge = e
75+
break
76+
77+
}
78+
79+
80+
//The child's label and the search string share a prefix
81+
else if shared.characters.count > 0 {
82+
83+
//Cut the prefix off from both the search string and label
84+
var labelIndex = e.label.characters.startIndex
85+
86+
for _ in 1...shared.characters.count {
87+
index = index.successor()
88+
labelIndex = labelIndex.successor()
89+
}
90+
91+
searchStr = searchStr.substringFromIndex(index)
92+
e.label = e.label.substringFromIndex(labelIndex)
93+
94+
//Create a new edge whose label is the shared string
95+
//its parent is currEdge.parent and add a child with
96+
//label = searchStr
97+
//Also add it to the parent's children
98+
let newEdge = Edge(shared)
99+
newEdge.children.append( Edge(searchStr) )
100+
newEdge.parent = e.parent
101+
currEdge.children.append(newEdge)
102+
103+
//Remove this edge from the parent's child list
104+
currEdge.children.remove(at: i)
105+
106+
//Set this edge's parent to the prefix node
107+
e.parent = newEdge.parent
108+
return true
109+
110+
}
111+
112+
//They don't share a prefix (go to next child)
113+
i += 1
114+
115+
}
116+
117+
//No children share a prefix, so create a new child
118+
currEdge.children.append( Edge(searchStr) )
119+
return true
120+
}
121+
}
122+
}
123+
124+
//Returns the prefix that is shared between the two input strings
125+
//i.e. sharedPrefix("court", "coral") -> "co"
126+
func sharedPrefix(_ str1: String, _ str2: String) -> String {
127+
128+
var temp = ""
129+
130+
var c1 = str1.characters.startIndex
131+
var c2 = str2.characters.startIndex
132+
133+
for _ in 0...min(str1.characters.count-1, str2.characters.count-1) {
134+
135+
if str1[c1] == str2[c2] {
136+
temp.append( str1[c1] )
137+
c1 = c1.successor()
138+
c2 = c2.successor()
139+
}
140+
141+
else {
142+
return temp
143+
}
144+
145+
}
146+
147+
return temp
148+
149+
}

Radix-Tree/RadixTree.swift

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import Foundation
2+
3+
4+
public class RadixNode {
5+
public var parent: RadixNode?
6+
public var children = [(childNode: RadixNode, childEdgeLabel: String)]()
7+
8+
public init() {
9+
10+
}
11+
12+
public init(value: String) {
13+
self.children.append((childNode: RadixNode(), childEdgeLabel: value))
14+
}
15+
16+
public func addChild(_ node: RadixNode, _ label: String) {
17+
children.append((node, label))
18+
node.parent = self
19+
}
20+
21+
public func getChildren() -> [(childNode: RadixNode, childEdgeLabel: String)] {
22+
return children
23+
}
24+
25+
public func getChildAt(i: Int) -> (RadixNode, String)? {
26+
if i >= children.count {
27+
return nil
28+
}
29+
return children[i]
30+
}
31+
32+
public func getParent() -> RadixNode? {
33+
return parent
34+
}
35+
36+
public func isLeaf() -> Bool {
37+
return children.count == 0
38+
}
39+
}
40+
41+
public class RadixTree {
42+
public var root: RadixNode
43+
44+
//Construct an "empty" RadixTree with a single node
45+
public init() {
46+
root = RadixNode()
47+
}
48+
49+
public init(value: String) {
50+
self.root = RadixNode(value: value)
51+
}
52+
53+
public func find(str: String, node: RadixNode?) -> Bool {
54+
var currNode: RadixNode
55+
var search = str
56+
if (node == nil) {
57+
currNode = self.root
58+
}
59+
else {
60+
currNode = node!
61+
}
62+
if (str == "") {
63+
return true
64+
}
65+
else {
66+
for n in 0...currNode.children.count-1 {
67+
if (str.hasPrefix(currNode.children[n].childEdgeLabel)) {
68+
let elementsFound = currNode.children[n].childEdgeLabel.characters.count
69+
search = search.substringFromIndex(search.startIndex.advanced(by: elementsFound))
70+
currNode = currNode.children[n].childNode
71+
find(str: search, node: currNode)
72+
}
73+
}
74+
}
75+
return false
76+
}
77+
78+
public func insert(str: String, node: RadixNode?) -> Bool {
79+
var search = str
80+
var currNode: RadixNode
81+
if (node == nil) {
82+
currNode = self.root
83+
}
84+
else {
85+
currNode = node!
86+
}
87+
//Case 0: str == "" (it is already in the tree)
88+
// -> return false
89+
if (str == "") {
90+
return false
91+
}
92+
else {
93+
for c in currNode.children {
94+
95+
//Temp is the string of the prefix that the label and the
96+
// search string have in common.
97+
//let temp = currNode.children[c].childEdgeLabel.sharePrefix(str)
98+
99+
//Case 3: currNode has a child that shares some prefix with str
100+
// -> little bit more complicated
101+
//if temp == 0 {
102+
103+
//Remove the shared characters from both the search string and
104+
// label
105+
//currNode.children[c].childEdgeLabel.substringFromIndex(temp.count)
106+
//str.substringFromIndex(temp.count)
107+
108+
109+
//}
110+
111+
112+
//Case 1: currNode has no children that share a prefix with str
113+
// -> create a new child for currNode
114+
115+
116+
//Case 2: currNode has a child whose label is a prefix of str
117+
// -> recurse down
118+
119+
}
120+
}
121+
return false
122+
}
123+
}

0 commit comments

Comments
 (0)