-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathttree.rb
More file actions
166 lines (144 loc) · 4.02 KB
/
ttree.rb
File metadata and controls
166 lines (144 loc) · 4.02 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Implementation of a ternary tree
# The ternary tree is much like a binary tree but with 3 child nodes for
# each parent instead of two - with the left node being values < parent,
# the right node values > parent, and the middle node values == parent.
#
# Author:: Mike Leary (mailto:mikeyfinn@gmail.com)
# Copyright:: Copyright (c) 2002 Mike Leary
# License:: Attribution-ShareAlike 2.5 Generic (CC BY-SA 2.5)
# This class can be used to instantiate a ternary tree two ways:
# 1) from the constructor by passing in an array of comparables,
# 2) by calling tree.add(item) on the ternary tree instance.
# You can always add more items using add().
#
class TernaryTree
Val = 0 unless const_defined?(:Val)
Left = 1 unless const_defined?(:Left)
Mid = 2 unless const_defined?(:Mid)
Right = 3 unless const_defined?(:Right)
# Create a new ternary tree, optionally passing in and array of comparable items
def initialize(int_ary=[])
# nodes are just an array of length 4, see constants above for magic
@root = mk_node()
if 0 < int_ary.length
@root[Val] = int_ary[0]
int_ary[1..(int_ary.length-1)].each do |i|
add(i)
end
end
end
# These are not the droids you're looking for
def mk_node # private
[nil] * 4
end
# Add a new item to the ternary tree instance.
# Item must be comparable to the other items in the tree, otherwise
# the behavior is not defined.
def add(val)
node = @root
# what you'd expect
# only create nodes as needed, on the fly, maintaining tree ref integrity
while true do
if node[Val] == nil
node[Val] = val
return
elsif val == node[Val]
if nil == node[Mid]
node = node[Mid] = mk_node()
else
node = node[Mid]
end
next
elsif val < node[Val]
if nil == node[Left]
node = node[Left] = mk_node()
else
node = node[Left]
end
next
else # val > node[Val]
if nil == node[Right]
node = node[Right] = mk_node()
else
node = node[Right]
end
next
end
end
end
# Compute and return the size of the left tree originating at node.
# Does NOT count node itself.
def left_size(node=@root)
size(node, Left)
end
# Compute and return the size of the mid tree originating at node.
# Does NOT count node itself.
def mid_size(node=@root)
size(node, Mid)
end
# Compute and return the size of the right tree originating at node.
# Does NOT count node itself.
def right_size(node=@root)
size(node, Right)
end
# Compute and return the size of the tree originating at node.
# DOES count node itself.
def total_size(node=@root)
1 + left_size() + mid_size() + right_size()
end
# These are not the droids you're looking for
def size(node, which) # private
# BFS, not that it matters too much here
size = 0
q = []
q.push(node[which])
while 0 < q.length
node = q.shift()
if nil == node
next
end
size += 1
if nil != node[Left]
q.push(node[Left])
end
if nil != node[Mid]
q.push(node[Mid])
end
if nil != node[Right]
q.push(node[Right])
end
end
size
end
# A string representation of the tree instance. Nothing pretty.
# Good for debugging.
def to_s
# BFS ... maybe refactor with to_s, but smaller, faster this way for most uses
s = "root:" + @root[Val].to_s + "\n"
node = @root
q = []
q.push(node)
while 0 < q.length
node = q.shift()
if nil == node
next
end
s += "node:" + node[Val].to_s
if nil != node[Left]
s += " left:" + node[Left][Val].to_s
q.push(node[Left])
end
if nil != node[Mid]
s += " mid:" + node[Mid][Val].to_s
q.push(node[Mid])
end
if nil != node[Right]
s += " right:" + node[Right][Val].to_s
q.push(node[Right])
end
s += "\n"
end
s
end
private :mk_node, :size
end