is103 1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/graphlab.rb +650 -0
- data/lib/is103.rb +3 -0
- data/lib/lineardslab.rb +395 -0
- data/lib/treelab.rb +418 -0
- metadata +55 -0
data/lib/is103.rb
ADDED
data/lib/lineardslab.rb
ADDED
@@ -0,0 +1,395 @@
|
|
1
|
+
module RubyLabs
|
2
|
+
|
3
|
+
module LinearDSLab
|
4
|
+
|
5
|
+
#VERSION 1.2
|
6
|
+
#Labelled top and bottom of stack, front and end of queue
|
7
|
+
#Added a line after Lab title
|
8
|
+
|
9
|
+
# A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class. This StackView object is being used to store the location of all the rectangles, and its corresponding values.
|
10
|
+
StackView = Struct.new(:cells, :values)
|
11
|
+
|
12
|
+
# Generates the view for a stack visualization
|
13
|
+
def view_stack(s, *peek)
|
14
|
+
# Initializes the canvas and font type
|
15
|
+
Canvas.init(400, 400, "Stack")
|
16
|
+
Canvas::Font.new('bucketfont', :family => 'Helvetica', :size => 11)
|
17
|
+
|
18
|
+
stack = s.items
|
19
|
+
|
20
|
+
cells = []
|
21
|
+
values = []
|
22
|
+
|
23
|
+
# Define starting height of first rectangle
|
24
|
+
y0 = 50
|
25
|
+
Canvas::Text.new("Stack Lab", 10, 1, {:font => :bucketfont})
|
26
|
+
Canvas::Line.new(0, 20, 400, 20, :fill => :gray, :width => 1)
|
27
|
+
|
28
|
+
# If generating a peek view, color first rectangle red, and place it on the right
|
29
|
+
if peek[0] && stack[0]
|
30
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
31
|
+
cells[0].fill = 'red'
|
32
|
+
y1 = y0+3
|
33
|
+
values << Canvas::Text.new(stack[0], 65, y0+3, {:font => :bucketfont})
|
34
|
+
Canvas::Text.new("<- Top of the Stack", 200, y1, {:font => :bucketfont})
|
35
|
+
|
36
|
+
# Else place a normal rectangle
|
37
|
+
elsif stack[0]
|
38
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
39
|
+
cells[0].fill = 'grey'
|
40
|
+
y1 = y0+3
|
41
|
+
values << Canvas::Text.new(stack[0], 65, y0+3, {:font => :bucketfont})
|
42
|
+
Canvas::Text.new("<- Top of the Stack", 200, y1, {:font => :bucketfont})
|
43
|
+
end
|
44
|
+
|
45
|
+
iterations = stack.length-1
|
46
|
+
|
47
|
+
# Iterate as many times as the number of elements in the array minus one. The first element is already handled above.
|
48
|
+
iterations.times do |i|
|
49
|
+
y0 += 25
|
50
|
+
# Draw a rectangle and store a reference to this rectangle in the cells array
|
51
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
52
|
+
cells[i+1].fill = 'grey'
|
53
|
+
# Draw the text value and store a reference to this value in the values array
|
54
|
+
values << Canvas::Text.new(stack[i+1], 65, y0+3, {:font => :bucketfont})
|
55
|
+
end
|
56
|
+
|
57
|
+
if stack.length-1 > 0
|
58
|
+
Canvas::Text.new("<- Bottom of the Stack", 200, y0+3, {:font => :bucketfont})
|
59
|
+
end
|
60
|
+
|
61
|
+
# Store the properties of this drawing as a Struct object
|
62
|
+
s.drawing = StackView.new(cells, values)
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
|
66
|
+
# Ruby Array-based implementation of a Stack
|
67
|
+
class Stack
|
68
|
+
|
69
|
+
# array used to store the values in the stack
|
70
|
+
attr_reader :items
|
71
|
+
# Struct object to store the attributes of the drawn visualization
|
72
|
+
attr_accessor :drawing
|
73
|
+
|
74
|
+
# class constructor
|
75
|
+
def initialize
|
76
|
+
@items = Array.new
|
77
|
+
end
|
78
|
+
|
79
|
+
# pop method. if a drawing exists, redraw the canvas
|
80
|
+
def pop
|
81
|
+
value = items.shift
|
82
|
+
if @drawing
|
83
|
+
view_stack(self, false)
|
84
|
+
end
|
85
|
+
return value
|
86
|
+
end
|
87
|
+
|
88
|
+
# peek method. if a drawing exists, redraw the canvas
|
89
|
+
def peek
|
90
|
+
if @drawing
|
91
|
+
view_stack(self, true)
|
92
|
+
end
|
93
|
+
return items.first
|
94
|
+
end
|
95
|
+
|
96
|
+
# push method. if a drawing exists, redraw the canvas
|
97
|
+
def push(value)
|
98
|
+
output = items.unshift(value)
|
99
|
+
if @drawing
|
100
|
+
view_stack(self, false)
|
101
|
+
end
|
102
|
+
return output
|
103
|
+
end
|
104
|
+
|
105
|
+
# return a string representation of the array
|
106
|
+
def inspect
|
107
|
+
return to_s
|
108
|
+
end
|
109
|
+
|
110
|
+
# returns a string representation of the array
|
111
|
+
def to_s
|
112
|
+
return @items.inspect
|
113
|
+
end
|
114
|
+
|
115
|
+
# returns the number of items currently in the stack
|
116
|
+
def count
|
117
|
+
return items.count
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# A Struct is a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class. This QueueView object is being used to store the location of all the rectangles, and its corresponding values.
|
122
|
+
QueueView = Struct.new(:cells, :values)
|
123
|
+
|
124
|
+
# Generates the view for a queue visualization
|
125
|
+
def view_queue(q, *peek)
|
126
|
+
# Initializes the canvas and font type
|
127
|
+
Canvas.init(400, 400, "Queue")
|
128
|
+
Canvas::Font.new('bucketfont', :family => 'Helvetica', :size => 11)
|
129
|
+
|
130
|
+
queue = q.items
|
131
|
+
|
132
|
+
cells = []
|
133
|
+
values = []
|
134
|
+
|
135
|
+
# Define starting height of first rectangle
|
136
|
+
y0 = 50
|
137
|
+
Canvas::Text.new("Queue Lab", 10, 1, {:font => :bucketfont})
|
138
|
+
Canvas::Line.new(0, 20, 400, 20, :fill => :gray, :width => 1)
|
139
|
+
|
140
|
+
# If generating a peek view, color last rectangle red, and place it on the right
|
141
|
+
if peek[0] && queue[0]
|
142
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
143
|
+
cells[0].fill = 'red'
|
144
|
+
y1 = y0+3
|
145
|
+
values << Canvas::Text.new(queue[0], 65, y1, {:font => :bucketfont})
|
146
|
+
Canvas::Text.new("<- Head of the Queue", 200, y1, {:font => :bucketfont})
|
147
|
+
|
148
|
+
# Else place a normal rectangle
|
149
|
+
elsif queue[0]
|
150
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
151
|
+
cells[0].fill = 'grey'
|
152
|
+
y1 = y0+3
|
153
|
+
values << Canvas::Text.new(queue[0], 65, y1, {:font => :bucketfont})
|
154
|
+
Canvas::Text.new("<- Head of the Queue", 200, y1, {:font => :bucketfont})
|
155
|
+
end
|
156
|
+
|
157
|
+
iterations = queue.length-1
|
158
|
+
|
159
|
+
# Iterate as many times as the number of elements in the array minus one. The first element is already handled above.
|
160
|
+
iterations.times do |i|
|
161
|
+
y0 += 25
|
162
|
+
# Draw a rectangle and store a reference to this rectangle in the cells array
|
163
|
+
cells << Canvas::Rectangle.new(10, y0, 60, y0+25)
|
164
|
+
cells[i+1].fill = 'grey'
|
165
|
+
# Draw the text value and store a reference to this value in the values array
|
166
|
+
values << Canvas::Text.new(queue[i+1], 65, y0+3, {:font => :bucketfont})
|
167
|
+
end
|
168
|
+
|
169
|
+
if queue.length-1 > 0
|
170
|
+
Canvas::Text.new("<- Tail of the Queue", 200, y0+3,{:font => :bucketfont})
|
171
|
+
end
|
172
|
+
|
173
|
+
# Store the properties of this drawing as a Struct object
|
174
|
+
q.drawing = QueueView.new(cells, values)
|
175
|
+
return true
|
176
|
+
end
|
177
|
+
|
178
|
+
# Ruby Array-based implementation of a queue
|
179
|
+
class Queue
|
180
|
+
|
181
|
+
# array used to store the values in the queue
|
182
|
+
attr_reader :items
|
183
|
+
# Struct object to store the attributes of the drawn visualization
|
184
|
+
attr_accessor :drawing
|
185
|
+
|
186
|
+
# class constructor
|
187
|
+
def initialize
|
188
|
+
@items = Array.new
|
189
|
+
end
|
190
|
+
|
191
|
+
# dequeue method. if a drawing exists, redraw the canvas
|
192
|
+
def dequeue
|
193
|
+
value = items.shift
|
194
|
+
if @drawing
|
195
|
+
view_queue(self, false)
|
196
|
+
end
|
197
|
+
return value
|
198
|
+
end
|
199
|
+
|
200
|
+
# peek method. if a drawing exists, redraw the canvas
|
201
|
+
def peek
|
202
|
+
if @drawing
|
203
|
+
view_queue(self, true)
|
204
|
+
end
|
205
|
+
return items.first
|
206
|
+
end
|
207
|
+
|
208
|
+
# enqueue method. if a drawing exists, redraw the canvas
|
209
|
+
def enqueue(value)
|
210
|
+
output = items << value
|
211
|
+
if @drawing
|
212
|
+
view_queue(self, false)
|
213
|
+
end
|
214
|
+
return output
|
215
|
+
end
|
216
|
+
|
217
|
+
# enqueue method. an alternative.
|
218
|
+
def <<(value)
|
219
|
+
output = items << value
|
220
|
+
if @drawing
|
221
|
+
view_queue(self, false)
|
222
|
+
end
|
223
|
+
return output
|
224
|
+
end
|
225
|
+
|
226
|
+
# dequeue method. an alternative.
|
227
|
+
def shift
|
228
|
+
value = items.shift
|
229
|
+
if @drawing
|
230
|
+
view_queue(self, false)
|
231
|
+
end
|
232
|
+
return value
|
233
|
+
end
|
234
|
+
|
235
|
+
# return a string representation of the array
|
236
|
+
def inspect
|
237
|
+
return to_s
|
238
|
+
end
|
239
|
+
|
240
|
+
# returns a string representation of the array
|
241
|
+
def to_s
|
242
|
+
return @items.inspect
|
243
|
+
end
|
244
|
+
|
245
|
+
# returns the number of items currently in the queue
|
246
|
+
def count
|
247
|
+
return items.count
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# checks whether an array is a palindrome using both stack and queue
|
252
|
+
# :begin :is_palindrome
|
253
|
+
def is_palindrome(v)
|
254
|
+
t = v.split(//)
|
255
|
+
q = Queue.new
|
256
|
+
s = Stack.new
|
257
|
+
t.each { |x| q.enqueue(x) }
|
258
|
+
t.each { |x| s.push(x) }
|
259
|
+
while s.count > 0
|
260
|
+
left = q.dequeue
|
261
|
+
right = s.pop
|
262
|
+
return false if(left != right)
|
263
|
+
end
|
264
|
+
return true
|
265
|
+
end
|
266
|
+
# :end :is_palindrome
|
267
|
+
|
268
|
+
# checks whether an array contains balanced braces using stack
|
269
|
+
# :begin :check_braces
|
270
|
+
def check_braces(t)
|
271
|
+
s = Stack.new
|
272
|
+
balancedSoFar = true
|
273
|
+
i = 0
|
274
|
+
while i < t.count and balancedSoFar
|
275
|
+
if t[i] == "{"
|
276
|
+
s.push(t[i])
|
277
|
+
elsif t[i] == "}"
|
278
|
+
if s.count > 0
|
279
|
+
s.pop
|
280
|
+
else
|
281
|
+
balancedSoFar = false
|
282
|
+
end
|
283
|
+
end
|
284
|
+
i += 1
|
285
|
+
end
|
286
|
+
return (balancedSoFar and s.count==0)
|
287
|
+
end
|
288
|
+
# :end :check_braces
|
289
|
+
|
290
|
+
# :begin :fibonacci_stack
|
291
|
+
def fibonacci_stack(n)
|
292
|
+
s = Stack.new
|
293
|
+
s.push(n)
|
294
|
+
result = 0
|
295
|
+
while s.count > 0
|
296
|
+
current = s.pop
|
297
|
+
if current == 0
|
298
|
+
result += 0
|
299
|
+
elsif current == 1
|
300
|
+
result += 1
|
301
|
+
else
|
302
|
+
s.push(current - 2)
|
303
|
+
s.push(current - 1)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
return result
|
307
|
+
end
|
308
|
+
# :end :fibonacci_stack
|
309
|
+
|
310
|
+
# :begin :fibonacci
|
311
|
+
def fibonacci(n)
|
312
|
+
if n == 0
|
313
|
+
return 0
|
314
|
+
elsif n == 1
|
315
|
+
return 1
|
316
|
+
else
|
317
|
+
return fibonacci(n-1) + fibonacci(n-2)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
# :end :fibonacci
|
321
|
+
|
322
|
+
# recursive version of binary search (from Conery's book)
|
323
|
+
# :begin :rbsearch
|
324
|
+
def rbsearch(a, k, lower = -1, upper = a.length)
|
325
|
+
mid = (lower + upper)/2
|
326
|
+
return nil if upper == lower + 1
|
327
|
+
return mid if k == a[mid]
|
328
|
+
|
329
|
+
if k < a[mid]
|
330
|
+
return rbsearch(a, k, lower, mid)
|
331
|
+
else
|
332
|
+
return rbsearch(a, k, mid, upper)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
# :end :rbsearch
|
336
|
+
|
337
|
+
# non-recursive, stack-based version of binary searh
|
338
|
+
# :begin :rbsearch_stack
|
339
|
+
def rbsearch_stack(a, k, lower = -1, upper = a.length)
|
340
|
+
s = Stack.new
|
341
|
+
s.push(lower)
|
342
|
+
s.push(upper)
|
343
|
+
while s.count > 0
|
344
|
+
upper = s.pop
|
345
|
+
lower = s.pop
|
346
|
+
mid = (lower + upper)/ 2
|
347
|
+
return nil if upper == lower + 1
|
348
|
+
return mid if k == a[mid]
|
349
|
+
if k < a[mid]
|
350
|
+
s.push(lower)
|
351
|
+
s.push(mid)
|
352
|
+
else
|
353
|
+
s.push(mid)
|
354
|
+
s.push(upper)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
# :end :rbsearch_stack
|
359
|
+
|
360
|
+
# This brackets method is taken from RubyLabs.
|
361
|
+
# A helper method that can be called from a probe to display the contents
|
362
|
+
# of an array during a search or sort. See also IterationLab#brackets.
|
363
|
+
#
|
364
|
+
# The version implemented in this module accepts an additional argument,
|
365
|
+
# which specifies the location of the right bracket in the output string
|
366
|
+
# (if this argument is not give the right bracket is inserted at the end).
|
367
|
+
#
|
368
|
+
# An optional third argument, intended for experiments with binary search, tells
|
369
|
+
# the method where to insert an asterisk before an item.
|
370
|
+
#
|
371
|
+
# Examples:
|
372
|
+
#
|
373
|
+
# >> a = TestArray.new(15)
|
374
|
+
# => [22, 3, 70, 74, 35, 0, 82, 64, 90, 54, 88, 26, 75, 18, 17]
|
375
|
+
# >> puts brackets(a, 8, 10)
|
376
|
+
# 22 3 70 74 35 0 82 64 [90 54 88] 26 75 18 17
|
377
|
+
# => nil
|
378
|
+
# >> puts brackets(a, 8, 10, 9)
|
379
|
+
# 22 3 70 74 35 0 82 64 [90 *54 88] 26 75 18 17
|
380
|
+
# => nil
|
381
|
+
#
|
382
|
+
def brackets(a, left, right = a.length-1, mid = nil)
|
383
|
+
left = 0 if left < 0
|
384
|
+
right = a.length-1 if right >= a.length
|
385
|
+
pre = left == 0 ? "" : " " + a.slice(0..(left-1)).join(" ") + " "
|
386
|
+
inner = left <= right ? a.slice(left..right).join(" ") : ""
|
387
|
+
post = " " + a.slice(right+1..-1).join(" ")
|
388
|
+
res = pre + "[" + inner + "]" + post
|
389
|
+
if mid && left < right
|
390
|
+
res[res.index(a[mid].to_s)-1] = ?*
|
391
|
+
end
|
392
|
+
return res
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
data/lib/treelab.rb
ADDED
@@ -0,0 +1,418 @@
|
|
1
|
+
module TreeLab
|
2
|
+
|
3
|
+
# Version 1.2 (27/09/2012)
|
4
|
+
# Changelog
|
5
|
+
# 1. Created Binary Search Tree class
|
6
|
+
#
|
7
|
+
# Version 1.1 (08/08/2012)
|
8
|
+
# Changelog
|
9
|
+
# 1. Changed node.leftChild to node.left, and node.rightChild to node.right
|
10
|
+
# 2. Merged preorder_traversal(*speed), inorder_traversal(*speed), postorder_traversal(*speed) into traversal(tree, option, *speed), where valid options are preorder, inorder, and postorder
|
11
|
+
# 3. Display text at end of traversal to indicate visit order: "Visited 9, 6, 5, 4"
|
12
|
+
# 4. Display order number during traversal
|
13
|
+
# 5. Tree animation now freezes at last frame
|
14
|
+
#
|
15
|
+
# Version 1.0 (06/08/2012)
|
16
|
+
# Changelog
|
17
|
+
# 1. Created Binary Tree, Node classes to represent a binary tree and a tree node
|
18
|
+
# 2. Created view_tree to visualize the tree and preorder_traversal, inorder_traversal, postorder_traversal to animate the traversal of a tree
|
19
|
+
|
20
|
+
@@tree = nil
|
21
|
+
@@visited = nil
|
22
|
+
@@sleep = 0.5
|
23
|
+
|
24
|
+
def view_tree(tree)
|
25
|
+
@@tree = tree
|
26
|
+
raise "Value must be a BinaryTree!" if !(tree.class == TreeLab::BinaryTree || tree.class == TreeLab::BinarySearchTree)
|
27
|
+
# Initializes the canvas and font type
|
28
|
+
Canvas.init(30+(2**tree.heightOfTree)*30, 50*tree.heightOfTree+50, "TreeLab")
|
29
|
+
Canvas::Font.new('bucketfont', :family => 'Helvetica', :size => 10)
|
30
|
+
|
31
|
+
# calls recursive method to draw the tree using post-order traversal
|
32
|
+
if tree.root == nil
|
33
|
+
return true
|
34
|
+
end
|
35
|
+
preOrder(tree.root, ((2**tree.heightOfTree)*30)/2, 30, ((2**tree.heightOfTree)*30)/2)
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
|
39
|
+
def tree
|
40
|
+
@@tree
|
41
|
+
end
|
42
|
+
|
43
|
+
def traversal(tree, option, *speed)
|
44
|
+
view_tree(tree)
|
45
|
+
if (!speed[0])
|
46
|
+
@@sleep = 0.5
|
47
|
+
else
|
48
|
+
@@sleep = speed[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
Canvas::Font.new('bucketfont', :family => 'Helvetica', :size => 10)
|
52
|
+
|
53
|
+
@@visited = Array.new
|
54
|
+
|
55
|
+
root = @@tree.root
|
56
|
+
sleep(1)
|
57
|
+
case option
|
58
|
+
when :preorder
|
59
|
+
preorder_traverse(root)
|
60
|
+
when :inorder
|
61
|
+
inorder_traverse(root)
|
62
|
+
when :postorder
|
63
|
+
postorder_traverse(root)
|
64
|
+
else
|
65
|
+
return "Invalid option. Valid options include :preorder, :inorder, :postorder"
|
66
|
+
end
|
67
|
+
sleep(1)
|
68
|
+
|
69
|
+
text = "Visited: "
|
70
|
+
|
71
|
+
@@visited.each_with_index {
|
72
|
+
|val, index|
|
73
|
+
text = text + val.to_s
|
74
|
+
if index != @@visited.length-1
|
75
|
+
text = text + ", "
|
76
|
+
end
|
77
|
+
}
|
78
|
+
return text
|
79
|
+
end
|
80
|
+
|
81
|
+
# Ruby Reference-based implementation of a Binary Tree
|
82
|
+
class BinaryTree
|
83
|
+
|
84
|
+
# root node
|
85
|
+
attr_reader :root
|
86
|
+
|
87
|
+
# class constructor
|
88
|
+
def initialize()
|
89
|
+
end
|
90
|
+
|
91
|
+
def setRoot(node)
|
92
|
+
raise "Value must be a Node!" if node.class != TreeLab::Node
|
93
|
+
raise "cannot attach node to itself" if node == self
|
94
|
+
@root = node
|
95
|
+
if(TreeLab::tree)
|
96
|
+
view_tree(TreeLab::tree)
|
97
|
+
end
|
98
|
+
return to_s
|
99
|
+
end
|
100
|
+
|
101
|
+
# checks whether the tree is empty
|
102
|
+
def isEmpty?
|
103
|
+
return root == nil
|
104
|
+
end
|
105
|
+
|
106
|
+
# counts number of nodes in the tree
|
107
|
+
def noOfNodes
|
108
|
+
if @root == nil
|
109
|
+
return 0
|
110
|
+
end
|
111
|
+
return countNode(@root)
|
112
|
+
end
|
113
|
+
|
114
|
+
# counts the height of the tree
|
115
|
+
def heightOfTree
|
116
|
+
if (@root == nil)
|
117
|
+
return 0
|
118
|
+
else
|
119
|
+
return countHeight(@root)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# empties the tree
|
124
|
+
def empty
|
125
|
+
@root = nil
|
126
|
+
if(TreeLab::tree)
|
127
|
+
view_tree(TreeLab::tree)
|
128
|
+
end
|
129
|
+
return true
|
130
|
+
end
|
131
|
+
|
132
|
+
def inspect
|
133
|
+
return to_s
|
134
|
+
end
|
135
|
+
|
136
|
+
# returns string representation of root node
|
137
|
+
def to_s
|
138
|
+
return nil if @root == nil
|
139
|
+
return @root.to_s
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
# private recursive method to count the number of nodes
|
144
|
+
def countNode(node)
|
145
|
+
if (node == nil)
|
146
|
+
return 0
|
147
|
+
end
|
148
|
+
if (node.isLeaf?)
|
149
|
+
return 1
|
150
|
+
end
|
151
|
+
return 1 + countNode(node.left) + countNode(node.right)
|
152
|
+
end
|
153
|
+
|
154
|
+
# private recursive method to count the height of the tree
|
155
|
+
def countHeight(node)
|
156
|
+
if (node == nil)
|
157
|
+
return 0
|
158
|
+
end
|
159
|
+
if (node.isLeaf?)
|
160
|
+
return 1
|
161
|
+
end
|
162
|
+
return 1 + [countHeight(node.left),countHeight(node.right)].max
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Node class used to represent each node in a binary tree
|
167
|
+
class Node
|
168
|
+
|
169
|
+
# left child of node
|
170
|
+
attr_reader:left
|
171
|
+
# right child of node
|
172
|
+
attr_reader:right
|
173
|
+
# value of node
|
174
|
+
attr_accessor:value
|
175
|
+
# attribute that represents the node in a binary tree canvas
|
176
|
+
attr_accessor:circle
|
177
|
+
|
178
|
+
def initialize(value)
|
179
|
+
@value = value
|
180
|
+
end
|
181
|
+
|
182
|
+
# sets the left child node
|
183
|
+
def setLeft(node)
|
184
|
+
raise "Value must be a Node!" if node.class != TreeLab::Node
|
185
|
+
raise "cannot attach node to itself" if node == self
|
186
|
+
raise "left child is not empty" if @left != nil
|
187
|
+
@left = node
|
188
|
+
if(TreeLab::tree)
|
189
|
+
view_tree(TreeLab::tree)
|
190
|
+
end
|
191
|
+
return to_s
|
192
|
+
end
|
193
|
+
|
194
|
+
# sets the right child node
|
195
|
+
def setRight(node)
|
196
|
+
raise "Value must be a Node!" if node.class != TreeLab::Node
|
197
|
+
raise "cannot attach node to itself" if node == self
|
198
|
+
raise "left child is not empty" if @right != nil
|
199
|
+
@right = node
|
200
|
+
if(TreeLab::tree)
|
201
|
+
view_tree(TreeLab::tree)
|
202
|
+
end
|
203
|
+
return to_s
|
204
|
+
end
|
205
|
+
|
206
|
+
# deletes the left child node
|
207
|
+
def delLeft
|
208
|
+
@left = nil
|
209
|
+
if(TreeLab::tree)
|
210
|
+
view_tree(TreeLab::tree)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# deletes the left child node
|
215
|
+
def delRight
|
216
|
+
@right = nil
|
217
|
+
if(TreeLab::tree)
|
218
|
+
view_tree(TreeLab::tree)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# checks whether this node is a leaf node
|
223
|
+
def isLeaf?
|
224
|
+
return (left == nil && right == nil);
|
225
|
+
end
|
226
|
+
|
227
|
+
# return a string representation of the node
|
228
|
+
def inspect
|
229
|
+
return to_s
|
230
|
+
end
|
231
|
+
|
232
|
+
# returns a string representation of the node
|
233
|
+
def to_s
|
234
|
+
s = "Value: "+value.to_s;
|
235
|
+
if (left != nil)
|
236
|
+
s += ", left child: "+left.value.to_s;
|
237
|
+
else
|
238
|
+
s += ", left child: nil"
|
239
|
+
end
|
240
|
+
if (right != nil)
|
241
|
+
s += ", right child: "+right.value.to_s;
|
242
|
+
else
|
243
|
+
s += ", right child: nil"
|
244
|
+
end
|
245
|
+
return s;
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
class BinarySearchTree < BinaryTree
|
250
|
+
|
251
|
+
# :begin :search
|
252
|
+
def search(key)
|
253
|
+
if !stable
|
254
|
+
p "Warning! Binary Search tree is not sorted correctly."
|
255
|
+
end
|
256
|
+
if(TreeLab::tree)
|
257
|
+
@@visited = Array.new
|
258
|
+
view_tree(self)
|
259
|
+
bstsearch(@root, key)
|
260
|
+
end
|
261
|
+
return searchbst(@root, key)
|
262
|
+
end
|
263
|
+
# :end :search
|
264
|
+
|
265
|
+
# :begin :insert
|
266
|
+
def insert(key)
|
267
|
+
if !stable
|
268
|
+
p "Warning! Binary Search tree is not sorted correctly."
|
269
|
+
end
|
270
|
+
if(TreeLab::tree)
|
271
|
+
@@visited = Array.new
|
272
|
+
view_tree(self)
|
273
|
+
bstsearch(@root, key)
|
274
|
+
end
|
275
|
+
node = insertbst(@root, key)
|
276
|
+
if(TreeLab::tree)
|
277
|
+
view_tree(TreeLab::tree)
|
278
|
+
end
|
279
|
+
|
280
|
+
return node
|
281
|
+
end
|
282
|
+
# :end :insert
|
283
|
+
|
284
|
+
def stable
|
285
|
+
@@stableChecker = Array.new
|
286
|
+
inorder_check(@root)
|
287
|
+
|
288
|
+
for i in 1..@@stableChecker.length-1
|
289
|
+
return false if @@stableChecker[i] < @@stableChecker[i-1]
|
290
|
+
end
|
291
|
+
return true
|
292
|
+
end
|
293
|
+
|
294
|
+
private
|
295
|
+
|
296
|
+
def inorder_check(root)
|
297
|
+
if (root != nil)
|
298
|
+
inorder_check(root.left)
|
299
|
+
@@stableChecker << root.value
|
300
|
+
inorder_check(root.right)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# :begin :insertbst
|
305
|
+
def insertbst(root, key)
|
306
|
+
if root.value == key
|
307
|
+
return root
|
308
|
+
elsif root.value > key
|
309
|
+
if root.left != nil
|
310
|
+
return insertbst(root.left, key)
|
311
|
+
else
|
312
|
+
node = Node.new(key)
|
313
|
+
root.setLeft(node)
|
314
|
+
return node
|
315
|
+
end
|
316
|
+
else
|
317
|
+
if root.right != nil
|
318
|
+
return insertbst(root.right, key)
|
319
|
+
else
|
320
|
+
node = Node.new(key)
|
321
|
+
root.setRight(node)
|
322
|
+
return node
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
# :end :insertbst
|
327
|
+
|
328
|
+
# :begin :searchbst
|
329
|
+
def searchbst(root, key)
|
330
|
+
if root.value == key
|
331
|
+
return root
|
332
|
+
elsif root.left != nil and root.value > key
|
333
|
+
return searchbst(root.left, key)
|
334
|
+
elsif root.right != nil and root.value < key
|
335
|
+
return searchbst(root.right, key)
|
336
|
+
else
|
337
|
+
return nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
# :end :searchbst
|
341
|
+
end
|
342
|
+
|
343
|
+
private
|
344
|
+
|
345
|
+
#private recursive method to draw the tree
|
346
|
+
def preOrder(t, x, y, width)
|
347
|
+
if (t != nil)
|
348
|
+
t.circle = Canvas::Circle.new(x, y, 15)
|
349
|
+
Canvas::Text.new(t.value, x, y, :anchor => :center)
|
350
|
+
if (t.left != nil)
|
351
|
+
Canvas::Line.new(x-15, y, x-(width/2), y+50-15)
|
352
|
+
end
|
353
|
+
preOrder(t.left, x-(width/2), y+50, width/2)
|
354
|
+
if (t.right != nil)
|
355
|
+
Canvas::Line.new(x+15, y, x+(width/2), y+50-15)
|
356
|
+
end
|
357
|
+
preOrder(t.right, x+(width/2), y+50, width/2)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# :begin :preorder_traverse
|
362
|
+
def preorder_traverse(node)
|
363
|
+
if (node != nil)
|
364
|
+
visit(node)
|
365
|
+
preorder_traverse(node.left)
|
366
|
+
preorder_traverse(node.right)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
# :end :preorder_traverse
|
370
|
+
|
371
|
+
# :begin :postorder_traverse
|
372
|
+
def postorder_traverse(node)
|
373
|
+
if (node != nil)
|
374
|
+
postorder_traverse(node.left)
|
375
|
+
postorder_traverse(node.right)
|
376
|
+
visit(node)
|
377
|
+
end
|
378
|
+
end
|
379
|
+
# :end :postorder_traverse
|
380
|
+
|
381
|
+
# :begin :inorder_traverse
|
382
|
+
def inorder_traverse(node)
|
383
|
+
if (node != nil)
|
384
|
+
inorder_traverse(node.left)
|
385
|
+
visit(node)
|
386
|
+
inorder_traverse(node.right)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
# :end :inorder_traverse
|
390
|
+
|
391
|
+
def bstsearch(node, val)
|
392
|
+
if (node != nil)
|
393
|
+
visit(node)
|
394
|
+
if (val == node.value)
|
395
|
+
|
396
|
+
elsif (val < node.value)
|
397
|
+
bstsearch(node.left, val)
|
398
|
+
else
|
399
|
+
bstsearch(node.right, val)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
# :begin :visit
|
405
|
+
def visit(node)
|
406
|
+
@@visited << node.value
|
407
|
+
Canvas::Text.new(@@visited.length, node.circle.coords[0]+11, node.circle.coords[1]+33, :font => 'bucketfont')
|
408
|
+
node.circle.fill = 'red'
|
409
|
+
sleep(@@sleep)
|
410
|
+
node.circle.fill = 'green'
|
411
|
+
end
|
412
|
+
# :end :visit
|
413
|
+
|
414
|
+
def updateVisitedText(value)
|
415
|
+
if (value == nil)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|