search_tree 1.1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 919b31f780576cc1906242bb950b6a1ee9e4cfd9c704e46bbf5a1f80509d6ddc
4
+ data.tar.gz: e585b587411334cc9f27579def854b5c38ad1fc9688af36f88f69eb70b834316
5
+ SHA512:
6
+ metadata.gz: a085087340e456d665f5dd2b4e98549cf34cd91dd8b37f42774fa5c5aa20e8b5407e4eb4a1f949a47d8ce3936f411594d6dfd78381b4ea5e10abb784a2673d30
7
+ data.tar.gz: 9d27ee80fcfddfb7168fb0cd413926f287c8cf9a4aedc6ce6ed21dc41f3ad9a70d62a35569764709ddfe951ef48977528b8f0037098f780c032b81629ea68539
@@ -0,0 +1,189 @@
1
+ # Search-tree - Open source search binary tree and bi-dimensional tree.
2
+
3
+ [![Forks][forks-shield]][forks-url] [![Stars][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![Inline docs][docs-shield]][docs-url] [![Twitter][twitter-shield]][twitter-url]
4
+
5
+ Search tree is an open-source binary and bi-dimensional tree gem for ruby.
6
+ For more information about why and how it was done visit my [article][article-url] in [Medium][medium-phalado].
7
+
8
+ <p align="center">
9
+ <a href="https://github.com/phalado/Search-tree/issues">Report Bug</a>
10
+ - <a href="https://github.com/phalado/Search-tree/issues">Request Feature</a>
11
+ </p>
12
+
13
+ <!-- TABLE OF CONTENTS -->
14
+ ## Table of Contents
15
+
16
+ * [Install and Usage](#install-and-usage)
17
+ * [Available Methods](#avaiable-methods)
18
+ * [New node](#new-node)
19
+ * [Search](#search)
20
+ * [Search node](#search_node)
21
+ * [Edit node](#edit_node)
22
+ * [Delete node](#delete-node)
23
+ * [Print tree](#print-tree)
24
+ * [Number of nodes](#number-of-nodes)
25
+ * [Get depth](#get-depth)
26
+ * [Is balanced](#is-balanced)
27
+ * [Balance](#balance)
28
+ * [Get nodes](#get-nodes)
29
+ * [New balance nodes](#new-balance-nodes)
30
+ * [New node balanced](#new-node-balanced)
31
+ * [Load file](#load-file)
32
+ * [Save file](#save-file)
33
+ * [Author and Contribution](#author-and-contribution)
34
+ * [License](#license)
35
+ * [Future Works](#future-works)
36
+
37
+ ## Install and Usage
38
+
39
+ Download the [gem file][gem-file] and use the following command to install:
40
+ ```bash
41
+ gem install search_tree-[version].gem
42
+ ```
43
+ After installing add
44
+ ```ruby
45
+ require 'search_tree'
46
+ ```
47
+ in your code and you can use its methods.
48
+
49
+ ## Available Methods
50
+
51
+ First, you have to create a new tree using the ``BinaryTree`` class, as for example below:
52
+
53
+ ```ruby
54
+ t = BinaryTree.new
55
+ ```
56
+ In the ``initialize`` method the **root** variable is defined as *nil*.
57
+
58
+ ### New node
59
+ ```ruby
60
+ new_node(node, x, *args)
61
+ ```
62
+ This method is used to create a new node in the tree. It receives the **node** where the search begins, **x** as the search parameter and the pointer **args** that will receive all the other arguments added to the node.
63
+
64
+ ### Search
65
+ ```ruby
66
+ search(x, node = @root)
67
+ ```
68
+ Returns *true* if, starting at the passed **node**, it finds a node with the search parameter **x** and *false* if it finds a *nil*.
69
+
70
+ ### Search node
71
+ ```ruby
72
+ search_node(x, node = @root)
73
+ ```
74
+ Like the previus one but instead of returning *true* or *false* returns the pointer to the node with search parameter **x** or *nil*.
75
+
76
+ ### Edit node
77
+ ```ruby
78
+ edit_node(x, *args)
79
+ ```
80
+ Locate the node with search parameter **x** and changer its *arguments* for the ones in **args**, if this node existis.
81
+
82
+ ### Delete node
83
+ ```ruby
84
+ delete_node(x)
85
+ ```
86
+ Delete the node with the dearch parameter **x**, if exists.
87
+
88
+ ### Print tree
89
+ ```ruby
90
+ print_tree(node = @root)
91
+ ```
92
+ Print the tree, or sub-tree starting at the passed **node**, in crescent search parameter order.
93
+
94
+ ### Number of nodes
95
+ ```ruby
96
+ number_nodes(node = @root)
97
+ ```
98
+ Return the number of nodes in the tree, or sub-tree starting at the passed **node**.
99
+
100
+ ### Get depth
101
+ ```ruby
102
+ get_depth(node = @root, depth = 1, maxdepth = 0)
103
+ ```
104
+ Return the depth of the tree, or sub-tree starting at the passed **node**. The **depth** and **maxdepth** are used as helpers inside the method.
105
+
106
+ ### Is balanced
107
+ ```ruby
108
+ is_balanced?
109
+ ```
110
+ Return *true* if the number of nodes is smaller than ``2 ^ (depth - 1)`` and bigger than ``2 ^ depth`` and *false* otherwise.
111
+
112
+ ### Balance
113
+ ```ruby
114
+ balance
115
+ ```
116
+ Balance the tree unless ``is_balanced?`` returns *true*.
117
+
118
+ ### Get nodes
119
+ ```ruby
120
+ get_nodes(nodes, node = @root)
121
+ ```
122
+ Return the array **nodes** with all the nodes in the crescent search parameter order in the tree or sub-tree starting at the passed **node**. Used to balance the tree.
123
+
124
+ ### New balance nodes
125
+ ```ruby
126
+ new_balance_nodes(nodes, newroot = @root)
127
+ ```
128
+ Used to create a new node with the array **nodes** received in the ``get_nodes`` method.
129
+
130
+ ### New node balanced
131
+ ```ruby
132
+ new_node_balanced(node, x, *args)
133
+ ```
134
+ Create a new node and balance the tree.
135
+
136
+ ### Load file
137
+ ```ruby
138
+ load_file(file)
139
+ ```
140
+ Create a tree with the data inside a file. The search parameter will always be a string.
141
+
142
+ ### Save file
143
+ ```ruby
144
+ save_file(file)
145
+ ```
146
+ Create a file with the data in the tree.
147
+
148
+ ## Author and Contribution
149
+
150
+ Add me at [linkedin][linkedin-url], send me an [email][phalado@gmail.com], visit my [twitter][twitter-url], [medium][medium-phalado] and [portfolio][my-portfolio].
151
+
152
+ Feel free to contribute with pull requests but, for major changes, please open an issue first.
153
+
154
+ ## License
155
+
156
+ Coming soon
157
+
158
+ ## Future works
159
+
160
+ Already started a load file and a save file methods.
161
+
162
+ Have a big ambition to create the bi-dimensional tree. I will do it in the next days.
163
+
164
+ <!-- MARKDOWN LINKS & IMAGES -->
165
+ <!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
166
+ [downloads-shield]: https://img.shields.io/github/downloads/phalado/Search-tree
167
+ [downloads-url]: https://github.com/ferreirati/mv-08-htmlcss-framework/graphs/contributors
168
+
169
+ [forks-shield]: https://img.shields.io/github/forks/phalado/Search-tree
170
+ [forks-url]: https://github.com/phalado/Search-tree/network/members
171
+
172
+ [stars-shield]: https://img.shields.io/github/stars/phalado/Search-tree
173
+ [stars-url]: https://github.com/phalado/Search-tree/stargazers
174
+
175
+ [issues-shield]: https://img.shields.io/github/issues/phalado/Search-tree
176
+ [issues-url]: https://github.com/phalado/Search-tree/issues
177
+
178
+ [docs-shield]: http://inch-ci.org/github/phalado/Search-tree.svg?branch=master
179
+ [docs-url]: http://inch-ci.org/github/phalado/Search-tree
180
+
181
+ [twitter-shield]: https://img.shields.io/twitter/url?url=https%3A%2F%2Fgithub.com%2Fphalado%2FSearch-tree%2F
182
+ [twitter-url]: https://twitter.com/Phalado
183
+ [article-url]: https://medium.com/p/bdfe7069be2d/
184
+ [medium-phalado]: https://medium.com/@phalado
185
+ [gem-file]: http://.com/
186
+ [linkedin-url]: https://www.linkedin.com/in/raphael-cordeiro/
187
+ [my-portfolio]: https://phalado.github.io/
188
+
189
+ [product-screenshot]: images/screenshot.png
@@ -0,0 +1,375 @@
1
+ class BiDimensionalTree
2
+ attr_reader :root
3
+
4
+ # Initialize the tree creating it's root
5
+ def initialize
6
+ @root = nil
7
+ end
8
+
9
+ # Create a new branch after locating it's place
10
+ def new_node(node, x, y, *args)
11
+ if @root.nil?
12
+ puts "Adding the node (#{x}, #{y}) in the root"
13
+ return @root = BiNode.new(x, y, *args)
14
+ elsif node.nil?
15
+ return node = BiNode.new(x, y, *args)
16
+ elsif node.x == x
17
+ if node.y == y
18
+ return node
19
+ elsif y < node.y
20
+ if node.south.nil?
21
+ puts "Adding the node (#{x}, #{y}) in the south of (#{node.x}, #{node.y})"
22
+ node.south = new_node(node.south, x, y, *args)
23
+ else
24
+ new_node(node.south, x, y, *args)
25
+ end
26
+ elsif y > node.y
27
+ if node.north.nil?
28
+ puts "Adding the node (#{x}, #{y}) in the north of (#{node.x}, #{node.y})"
29
+ node.north = new_node(node.north, x, y, *args)
30
+ else
31
+ new_node(node.north, x, y, *args)
32
+ end
33
+ end
34
+ elsif x < node.x
35
+ if node.west.nil?
36
+ puts "Adding the node (#{x}, #{y}) in the west of (#{node.x}, #{node.y})"
37
+ node.west = new_node(node.west, x, y, *args)
38
+ else
39
+ new_node(node.west, x, y, *args)
40
+ end
41
+ elsif x > node.x
42
+ if node.east.nil?
43
+ puts "Adding the node (#{x}, #{y}) in the east of (#{node.x}, #{node.y})"
44
+ node.east = new_node(node.east, x, y, *args)
45
+ else
46
+ new_node(node.east, x, y, *args)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Create a new node and balance the tree
52
+ def new_node_balanced(node, x, y, *args)
53
+ new_node(node, x, y, *args)
54
+ balance
55
+ end
56
+
57
+ # Locate a branch, if it exists
58
+ def search(x, y, node = @root)
59
+ return false if node.nil?
60
+
61
+ if x == node.x
62
+ if y == node.y
63
+ return true
64
+ elsif y < node.y and !node.south.nil?
65
+ search(x, y, node.south)
66
+ elsif y > node.y and !node.north.nil?
67
+ search(x, y, node.north)
68
+ else
69
+ return false
70
+ end
71
+ elsif x < node.x and !node.west.nil?
72
+ search(x, y, node.west)
73
+ elsif x > node.x and !node.east.nil?
74
+ search(x, y, node.east)
75
+ else
76
+ return false
77
+ end
78
+ end
79
+
80
+ # Locate a branch, if it exists
81
+ def search_node(x, y, node = @root)
82
+ return nil if node.nil?
83
+
84
+ if x == node.x
85
+ if y == node.y
86
+ return node
87
+ elsif y < node.y and !node.south.nil?
88
+ search_node(x, y, node.south)
89
+ elsif y > node.y and !node.north.nil?
90
+ search_node(x, y, node.north)
91
+ else
92
+ return nil
93
+ end
94
+ elsif x < node.x and !node.west.nil?
95
+ search_node(x, y, node.west)
96
+ elsif x > node.x and !node.east.nil?
97
+ search_node(x, y, node.east)
98
+ else
99
+ return nil
100
+ end
101
+ end
102
+
103
+ # Edit an existing node
104
+ def edit_node(x, y, *args)
105
+ node = search_node(x, y)
106
+ return if node.nil?
107
+ node.args = args
108
+ end
109
+
110
+ # Load a file and create a (sub)tree with its data
111
+ def load_file(file)
112
+ data = File.open(file).readlines.map(&:chomp)
113
+ data.each do |d|
114
+ d = d.split(',')
115
+ new_node(@root, *d[0], *d[1], *d[2..-1]) unless d.nil?
116
+ end
117
+ end
118
+
119
+ # Save the current tree in a file
120
+ def save_file
121
+ nodes = get_nodes([])
122
+ file = File.open('search_tree', 'w')
123
+ nodes.each do |node|
124
+ file.puts("#{node.x} #{node.y} #{node.args}")
125
+ end
126
+ file.close
127
+ end
128
+
129
+ # Print all the branchs
130
+ def print_tree(node = @root)
131
+ return if node.nil?
132
+ print_tree(node.west) unless node.west.nil?
133
+ print_tree(node.south) unless node.south.nil?
134
+ puts "#{node.x} #{node.y} #{node.args}"
135
+ print_tree(node.north) unless node.north.nil?
136
+ print_tree(node.east) unless node.east.nil?
137
+ return
138
+ end
139
+
140
+ # Delete a selected node from the tree
141
+ def delete_node(x, y)
142
+ node = search_node(x, y)
143
+ nodes = get_nodes_horiz([])
144
+ if nodes.include? node
145
+ nodes.delete(node)
146
+ @root = nodes[nodes.length / 2]
147
+ @root.west = nil
148
+ @root.east = nil
149
+
150
+ @root.west = new_balance_nodes_horiz(nodes[0..(nodes.length / 2) - 1])
151
+ @root.east = new_balance_nodes_horiz(nodes[(nodes.length / 2) + 1..-1])
152
+ else
153
+ nodes = get_column(node)
154
+ nodes.delete(node)
155
+ middle = nodes[nodes.length / 2]
156
+ middle.south = nil
157
+ middle.north = nil
158
+
159
+ middle.south = new_balance_nodes_vert(nodes[0..(nodes.length / 2) - 1])
160
+ middle.north = new_balance_nodes_vert(nodes[(nodes.length / 2) + 1..-1])
161
+ end
162
+ end
163
+
164
+ # Balance the tree
165
+ def balance_vert(node = @root)
166
+ unless balanced_vert_helper(node)
167
+ balance_vert_helper(node, node)
168
+ end
169
+ unless node.east.nil?
170
+ unless balanced_vert_helper(node.east)
171
+ node.east = balance_vert_helper(node.east, node.east)
172
+ else
173
+ balance_vert(node.east)
174
+ end
175
+ end
176
+ unless node.west.nil?
177
+ unless balanced_vert_helper(node.west)
178
+ node.west = balance_vert_helper(node.west, node.west)
179
+ else
180
+ balance_vert(node.west)
181
+ end
182
+ end
183
+ end
184
+
185
+ def balance_horiz(node = @root)
186
+ return if balanced_horiz?
187
+
188
+ nodes = get_nodes_horiz([], node)
189
+
190
+ @root = nodes[nodes.length / 2]
191
+ @root.west = nil
192
+ @root.east = nil
193
+
194
+ @root.west = new_balance_nodes_horiz(nodes[0..(nodes.length / 2) - 1])
195
+ @root.east = new_balance_nodes_horiz(nodes[(nodes.length / 2) + 1..-1])
196
+ end
197
+
198
+ # Return true if tree is balanced, in other word,
199
+ # if the number of branchs is smaller than 2 raised
200
+ # to the tree's depth
201
+ def balanced_horiz?
202
+ number_nodes_horiz.between?(2**(get_depth_horiz - 1), 2**get_depth_horiz)
203
+ end
204
+
205
+ def balanced_vert?(node = @root)
206
+ return false unless balanced_vert_helper(node)
207
+ unless node.east.nil?
208
+ return false unless balanced_vert?(node.east)
209
+ end
210
+ unless node.west.nil?
211
+ return false unless balanced_vert?(node.west)
212
+ end
213
+ true
214
+ end
215
+
216
+ def balance
217
+ balance_horiz unless balanced_horiz?
218
+ balance_vert unless balanced_vert?
219
+ end
220
+
221
+ def balanced_tree
222
+ return false unless balanced_horiz?
223
+ return false unless balanced_vert?
224
+ true
225
+ end
226
+
227
+ # Return the max depth of the tree
228
+ def get_depth_horiz(node = @root, depth = 1, maxdepth = 0)
229
+ unless node.west.nil?
230
+ maxdepth = get_depth_horiz(node.west, depth + 1, maxdepth)
231
+ end
232
+
233
+ unless node.east.nil?
234
+ maxdepth = get_depth_horiz(node.east, depth + 1, maxdepth)
235
+ end
236
+
237
+ if node.west.nil? and node.east.nil? and depth > maxdepth
238
+ maxdepth = depth
239
+ end
240
+
241
+ maxdepth
242
+ end
243
+
244
+ def get_depth_vert(node = @root, depth = 1, maxdepth = 0)
245
+ unless node.south.nil?
246
+ maxdepth = get_depth_vert(node.south, depth + 1, maxdepth)
247
+ end
248
+
249
+ unless node.north.nil?
250
+ maxdepth = get_depth_vert(node.north, depth + 1, maxdepth)
251
+ end
252
+
253
+ if node.south.nil? and node.north.nil? and depth > maxdepth
254
+ maxdepth = depth
255
+ end
256
+
257
+ maxdepth
258
+ end
259
+
260
+ # Return the number of branchs
261
+ def number_nodes_horiz(node = @root)
262
+ if node.nil?
263
+ 0
264
+ else
265
+ 1 +
266
+ number_nodes_horiz(node.west) +
267
+ number_nodes_horiz(node.east)
268
+ end
269
+ end
270
+
271
+ def number_nodes_vert(node = @root)
272
+ if node.nil?
273
+ 0
274
+ else
275
+ 1 +
276
+ number_nodes_vert(node.south) +
277
+ number_nodes_vert(node.north)
278
+ end
279
+ end
280
+
281
+ def number_nodes_total(node = @root)
282
+ if node.nil?
283
+ 0
284
+ else
285
+ 1 +
286
+ number_nodes_total(node.west) +
287
+ number_nodes_total(node.east) +
288
+ number_nodes_total(node.south) +
289
+ number_nodes_total(node.north)
290
+ end
291
+ end
292
+
293
+ private
294
+
295
+ # Return all the nodes in crescent order
296
+ def get_nodes_horiz(nodes, node = @root)
297
+ nodes = get_nodes_horiz(nodes, node.west) unless node.west.nil?
298
+ nodes << node
299
+ nodes = get_nodes_horiz(nodes, node.east) unless node.east.nil?
300
+ return nodes
301
+ end
302
+
303
+ def new_balance_nodes_horiz(nodes)
304
+ return nil if nodes.empty?
305
+
306
+ new_middle = nodes[nodes.length / 2]
307
+ new_middle.east = nil
308
+ new_middle.west = nil
309
+
310
+ return new_middle if nodes.length == 1
311
+
312
+ new_middle.west = new_balance_nodes_horiz(nodes[0..(nodes.length / 2) - 1])
313
+ new_middle.east = new_balance_nodes_horiz(nodes[(nodes.length / 2) + 1..-1])
314
+
315
+ return new_middle
316
+ end
317
+
318
+ def get_nodes_vert(nodes, node = @root)
319
+ nodes = get_nodes_vert(nodes, node.south) unless node.south.nil?
320
+ nodes << node
321
+ nodes = get_nodes_vert(nodes, node.north) unless node.north.nil?
322
+ return nodes
323
+ end
324
+
325
+ def balance_vert_helper(node, partial_root)
326
+ nodes = get_nodes_vert([], node)
327
+
328
+ middle = nodes[nodes.length / 2]
329
+ if partial_root.east
330
+ middle.east = partial_root.east
331
+ partial_root.east = nil
332
+ end
333
+ if partial_root.west
334
+ middle.west = partial_root.west
335
+ partial_root.west = nil
336
+ end
337
+ middle.north = nil
338
+ middle.south = nil
339
+
340
+ middle.south = new_balance_nodes_vert(nodes[0..(nodes.length / 2) - 1])
341
+ middle.north = new_balance_nodes_vert(nodes[(nodes.length / 2) + 1..-1])
342
+
343
+ return middle
344
+ end
345
+
346
+ def new_balance_nodes_vert(nodes)
347
+ return nil if nodes.empty?
348
+
349
+ new_middle = nodes[nodes.length / 2]
350
+ new_middle.north = nil
351
+ new_middle.south = nil
352
+
353
+ return new_middle if nodes.length == 1
354
+
355
+ new_middle.south = new_balance_nodes_vert(nodes[0..(nodes.length / 2) - 1])
356
+ new_middle.north = new_balance_nodes_vert(nodes[(nodes.length / 2) + 1..-1])
357
+
358
+ return new_middle
359
+ end
360
+
361
+ def balanced_vert_helper(node)
362
+ number_nodes_vert(node).between?(2**(get_depth_vert(node) - 1), 2**get_depth_vert(node))
363
+ end
364
+
365
+ def get_column(node, middle = @root)
366
+ return [] if middle.nil?
367
+ nodes = get_nodes_vert([], middle)
368
+ return nodes if nodes.include? node
369
+ nodes = get_column(node, middle.west) unless middle.west.nil?
370
+ return nodes if nodes.include? node
371
+ nodes = get_column(node, middle.east) unless middle.east.nil?
372
+ return nodes if nodes.include? node
373
+ return []
374
+ end
375
+ end
@@ -0,0 +1,12 @@
1
+ class BiNode
2
+ attr_reader :x, :y
3
+ attr_accessor :east, :west, :north, :south, :args
4
+
5
+ # Create the tree's root with the base values x
6
+ # and y and an unkown number of arguments.
7
+ def initialize(x, y, *args)
8
+ @x = x
9
+ @y = y
10
+ @args = args
11
+ end
12
+ end
@@ -0,0 +1,153 @@
1
+ class BinaryTree
2
+ attr_reader :root
3
+
4
+ # Initialize the tree creating it's root
5
+ def initialize
6
+ @root = nil
7
+ end
8
+
9
+ # Create a new branch after locating it's place
10
+ def new_node(node, x, *args)
11
+ return @root = Node.new(x, *args) if @root.nil?
12
+ return Node.new(x, *args) if node.nil?
13
+ return node if node.x == x
14
+
15
+ if x < node.x
16
+ if node.west.nil?
17
+ node.west = new_node(node.west, x, *args)
18
+ else
19
+ new_node(node.west, x, *args)
20
+ end
21
+ elsif node.east.nil?
22
+ node.east = new_node(node.east, x, *args)
23
+ else
24
+ new_node(node.east, x, *args)
25
+ end
26
+ end
27
+
28
+ # Create a new node and balance the tree
29
+ def new_node_balanced(node, x, *args)
30
+ new_node(node, x, *args)
31
+ balance unless balanced?
32
+ end
33
+
34
+ # Edit an existing node
35
+ def edit_node(x, *args)
36
+ node = search_node(x)
37
+ return if node.nil?
38
+ node.args = args
39
+ end
40
+
41
+ # Load a file and create a (sub)tree with its data
42
+ def load_file(file)
43
+ data = File.open(file).readlines.map(&:chomp)
44
+ data.each do |d|
45
+ d = d.split(',')
46
+ new_node(@root, *d[0], *d[1..-1]) unless d.nil?
47
+ end
48
+ end
49
+
50
+ # Save the current tree in a file
51
+ def save_file
52
+ nodes = get_nodes([])
53
+ file = File.open('search_tree', 'w')
54
+ nodes.each do |node|
55
+ file.puts("#{node.x} #{node.args}")
56
+ end
57
+ file.close
58
+ end
59
+
60
+ # Delete a selected node from the tree
61
+ def delete_node(x)
62
+ nodes = get_nodes([])
63
+ node = search_node(x)
64
+ nodes.delete(node) if nodes.include? node
65
+ @root = nil
66
+ new_balance_nodes(nodes, @root)
67
+ end
68
+
69
+ # Locate a branch, if it exists
70
+ def search(x, node = @root)
71
+ return false if node.nil?
72
+
73
+ if x == node.x
74
+ return true
75
+ elsif x < node.x && !node.west.nil?
76
+ search(x, node.west)
77
+ elsif x > node.x && !node.east.nil?
78
+ search(x, node.east)
79
+ else
80
+ return false
81
+ end
82
+ end
83
+
84
+ # Locate a branch, if it exists
85
+ def search_node(x, node = @root)
86
+ return nil if node.nil?
87
+
88
+ if x == node.x
89
+ return node
90
+ elsif x < node.x && !node.west.nil?
91
+ search_node(x, node.west)
92
+ elsif x > node.x && !node.east.nil?
93
+ search_node(x, node.east)
94
+ else
95
+ return nil
96
+ end
97
+ end
98
+
99
+ # Print all the branchs
100
+ def print_tree(node = @root)
101
+ return if node.nil?
102
+ print_tree(node.west) unless node.west.nil?
103
+ puts "#{node.x} #{node.args}"
104
+ print_tree(node.east) unless node.east.nil?
105
+ end
106
+
107
+ # Return all the nodes in crescent order
108
+ def get_nodes(nodes, node = @root)
109
+ nodes = get_nodes(nodes, node.west) unless node.west.nil?
110
+ nodes << node
111
+ nodes = get_nodes(nodes, node.east) unless node.east.nil?
112
+ nodes
113
+ end
114
+
115
+ # Balance the tree
116
+ def balance
117
+ unless balanced?
118
+ nodes = get_nodes([])
119
+ @root = nil
120
+ new_balance_nodes(nodes, @root)
121
+ end
122
+ end
123
+
124
+ def new_balance_nodes(nodes, newroot = @root)
125
+ # p nodes
126
+ return if nodes.empty?
127
+ new_node(newroot, nodes[nodes.length / 2].x, *nodes[nodes.length / 2].args)
128
+ return if nodes.length == 1
129
+ new_balance_nodes(nodes[0..(nodes.length / 2) - 1], @root)
130
+ new_balance_nodes(nodes[(nodes.length / 2) + 1..-1], @root)
131
+ end
132
+
133
+ # Return true if tree is balanced, in other word,
134
+ # if the number of branchs is smaller than 2 raised
135
+ # to the tree's depth
136
+ def balanced?
137
+ number_nodes.between?(2**(get_depth - 1), 2**get_depth)
138
+ end
139
+
140
+ # Return the max depth of the tree
141
+ def get_depth(node = @root, depth = 1, maxdepth = 0)
142
+ maxdepth = get_depth(node.west, depth + 1, maxdepth) unless node.west.nil?
143
+ maxdepth = get_depth(node.east, depth + 1, maxdepth) unless node.east.nil?
144
+ maxdepth = depth if node.west.nil? && node.east.nil? && depth > maxdepth
145
+
146
+ maxdepth
147
+ end
148
+
149
+ # Return the number of branchs
150
+ def number_nodes(node = @root)
151
+ node.nil? ? 0 : 1 + number_nodes(node.west) + number_nodes(node.east)
152
+ end
153
+ end
@@ -0,0 +1,11 @@
1
+ class Node
2
+ attr_reader :x
3
+ attr_accessor :east, :west, :args
4
+
5
+ # Create the tree's root with the base value x
6
+ # and an unkown number of arguments.
7
+ def initialize(x, *args)
8
+ @x = x
9
+ @args = args
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ require './lib/binary-tree-access.rb'
2
+ require './lib/binary-tree-node.rb'
3
+ require './lib/bi-dimensional-node.rb'
4
+ require './lib/bi-dimensional-access.rb'
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: search_tree
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0.2
5
+ platform: ruby
6
+ authors:
7
+ - "@Phalado"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: phalado@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.md
20
+ - lib/bi-dimensional-access.rb
21
+ - lib/bi-dimensional-node.rb
22
+ - lib/binary-tree-access.rb
23
+ - lib/binary-tree-node.rb
24
+ - lib/search_tree.rb
25
+ homepage: https://github.com/phalado/Search-tree/
26
+ licenses: []
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubygems_version: 3.0.6
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Open-source binary and bi-dimensional tree for ruby.
47
+ test_files: []