victory 0.0.0 → 0.0.1

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.rubocop.yml +11 -1
  4. data/README.md +4 -6
  5. data/Rakefile +11 -4
  6. data/USAGE.md +159 -0
  7. data/ext/algorithms/string/LICENSE.md +21 -0
  8. data/ext/algorithms/string/extconf.rb +4 -0
  9. data/ext/algorithms/string/string.c +68 -0
  10. data/ext/containers/bst/LICENSE.md +21 -0
  11. data/ext/containers/bst/bst.c +247 -0
  12. data/ext/containers/bst/extconf.rb +4 -0
  13. data/ext/containers/deque/LICENSE.md +21 -0
  14. data/ext/containers/deque/deque.c +247 -0
  15. data/ext/containers/deque/extconf.rb +4 -0
  16. data/ext/containers/rbtree_map/LICENSE.md +21 -0
  17. data/ext/containers/rbtree_map/extconf.rb +4 -0
  18. data/ext/containers/rbtree_map/rbtree.c +498 -0
  19. data/ext/containers/splaytree_map/LICENSE.md +21 -0
  20. data/ext/containers/splaytree_map/extconf.rb +4 -0
  21. data/ext/containers/splaytree_map/splaytree.c +419 -0
  22. data/ext/containers/xor_list/extconf.rb +4 -0
  23. data/ext/containers/xor_list/xor_list.c +122 -0
  24. data/lib/algorithms/search.rb +104 -0
  25. data/lib/algorithms/sort.rb +389 -0
  26. data/lib/algorithms/string.rb +29 -0
  27. data/lib/containers/deque.rb +193 -0
  28. data/lib/containers/heap.rb +524 -0
  29. data/lib/containers/kd_tree.rb +131 -0
  30. data/lib/containers/list.rb +81 -0
  31. data/lib/containers/prefix_tree.rb +61 -0
  32. data/lib/containers/priority_queue.rb +135 -0
  33. data/lib/containers/queue.rb +89 -0
  34. data/lib/containers/rb_tree_map.rb +420 -0
  35. data/lib/containers/splay_tree_map.rb +290 -0
  36. data/lib/containers/stack.rb +88 -0
  37. data/lib/containers/suffix_array.rb +92 -0
  38. data/lib/containers/trie.rb +204 -0
  39. data/lib/containers/tuple.rb +20 -0
  40. data/lib/victory/version.rb +1 -1
  41. data/lib/victory.rb +8 -1
  42. data/victory.gemspec +12 -3
  43. metadata +73 -12
  44. data/.idea/encodings.xml +0 -4
  45. data/.idea/misc.xml +0 -7
  46. data/.idea/modules.xml +0 -8
  47. data/.idea/victory.iml +0 -13
  48. data/.idea/workspace.xml +0 -233
  49. data/ext/victory/extconf.rb +0 -3
  50. data/ext/victory/victory.c +0 -9
  51. data/ext/victory/victory.h +0 -6
@@ -0,0 +1,524 @@
1
+ # rdoc
2
+ # A Heap is a container that satisfies the heap property that nodes are always smaller in
3
+ # value than their parent node.
4
+ #
5
+ # The Containers::Heap class is flexible and upon initialization, takes an optional block
6
+ # that determines how the items are ordered. Two versions that are included are the
7
+ # Containers::MaxHeap and Containers::MinHeap that return the largest and smallest items on
8
+ # each invocation, respectively.
9
+ #
10
+ # This library implements a Fibonacci heap, which allows O(1) complexity for most methods.
11
+ #
12
+ #
13
+ # MIT License
14
+ #
15
+ # Copyright (c) 2009 Kanwei Li
16
+ #
17
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ # of this software and associated documentation files (the "Software"), to deal
19
+ # in the Software without restriction, including without limitation the rights
20
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ # copies of the Software, and to permit persons to whom the Software is
22
+ # furnished to do so, subject to the following conditions:
23
+ #
24
+ # The above copyright notice and this permission notice shall be included in all
25
+ # copies or substantial portions of the Software.
26
+ #
27
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ # SOFTWARE.
34
+ class Containers::Heap
35
+ include Enumerable
36
+
37
+ # call-seq:
38
+ # size -> int
39
+ #
40
+ # Return the number of elements in the heap.
41
+ def size
42
+ @size
43
+ end
44
+ alias_method :length, :size
45
+
46
+ # call-seq:
47
+ # Heap.new(optional_array) { |x, y| optional_comparison_fn } -> new_heap
48
+ #
49
+ # If an optional array is passed, the entries in the array are inserted into the heap with
50
+ # equal key and value fields. Also, an optional block can be passed to define the function
51
+ # that maintains heap property. For example, a min-heap can be created with:
52
+ #
53
+ # minheap = Heap.new { |x, y| (x <=> y) == -1 }
54
+ # minheap.push(6)
55
+ # minheap.push(10)
56
+ # minheap.pop #=> 6
57
+ #
58
+ # Thus, smaller elements will be parent nodes. The heap defaults to a min-heap if no block
59
+ # is given.
60
+ def initialize(ary=[], &block)
61
+ @compare_fn = block || lambda { |x, y| (x <=> y) == -1 }
62
+ @next = nil
63
+ @size = 0
64
+ @stored = {}
65
+
66
+ ary.each { |n| push(n) } unless ary.empty?
67
+ end
68
+
69
+ # call-seq:
70
+ # push(key, value) -> value
71
+ # push(value) -> value
72
+ #
73
+ # Inserts an item with a given key into the heap. If only one parameter is given,
74
+ # the key is set to the value.
75
+ #
76
+ # Complexity: O(1)
77
+ #
78
+ # heap = MinHeap.new
79
+ # heap.push(1, "Cat")
80
+ # heap.push(2)
81
+ # heap.pop #=> "Cat"
82
+ # heap.pop #=> 2
83
+ def push(key, value=key)
84
+ raise ArgumentError, "Heap keys must not be nil." unless key
85
+ node = Node.new(key, value)
86
+ # Add new node to the left of the @next node
87
+ if @next
88
+ node.right = @next
89
+ node.left = @next.left
90
+ node.left.right = node
91
+ @next.left = node
92
+ if @compare_fn[key, @next.key]
93
+ @next = node
94
+ end
95
+ else
96
+ @next = node
97
+ end
98
+ @size += 1
99
+
100
+ arr = []
101
+ w = @next.right
102
+ until w == @next do
103
+ arr << w.value
104
+ w = w.right
105
+ end
106
+ arr << @next.value
107
+ @stored[key] ||= []
108
+ @stored[key] << node
109
+ value
110
+ end
111
+ alias_method :<<, :push
112
+
113
+ # call-seq:
114
+ # has_key?(key) -> true or false
115
+ #
116
+ # Returns true if heap contains the key.
117
+ #
118
+ # Complexity: O(1)
119
+ #
120
+ # minheap = MinHeap.new([1, 2])
121
+ # minheap.has_key?(2) #=> true
122
+ # minheap.has_key?(4) #=> false
123
+ def has_key?(key)
124
+ @stored[key] && !@stored[key].empty? ? true : false
125
+ end
126
+
127
+ # call-seq:
128
+ # next -> value
129
+ # next -> nil
130
+ #
131
+ # Returns the value of the next item in heap order, but does not remove it.
132
+ #
133
+ # Complexity: O(1)
134
+ #
135
+ # minheap = MinHeap.new([1, 2])
136
+ # minheap.next #=> 1
137
+ # minheap.size #=> 2
138
+ def next
139
+ @next && @next.value
140
+ end
141
+
142
+ # call-seq:
143
+ # next_key -> key
144
+ # next_key -> nil
145
+ #
146
+ # Returns the key associated with the next item in heap order, but does not remove the value.
147
+ #
148
+ # Complexity: O(1)
149
+ #
150
+ # minheap = MinHeap.new
151
+ # minheap.push(1, :a)
152
+ # minheap.next_key #=> 1
153
+ #
154
+ def next_key
155
+ @next && @next.key
156
+ end
157
+
158
+ # call-seq:
159
+ # clear -> nil
160
+ #
161
+ # Removes all elements from the heap, destructively.
162
+ #
163
+ # Complexity: O(1)
164
+ #
165
+ def clear
166
+ @next = nil
167
+ @size = 0
168
+ @stored = {}
169
+ nil
170
+ end
171
+
172
+ # call-seq:
173
+ # empty? -> true or false
174
+ #
175
+ # Returns true if the heap is empty, false otherwise.
176
+ def empty?
177
+ @next.nil?
178
+ end
179
+
180
+ # call-seq:
181
+ # merge!(otherheap) -> merged_heap
182
+ #
183
+ # Does a shallow merge of all the nodes in the other heap.
184
+ #
185
+ # Complexity: O(1)
186
+ #
187
+ # heap = MinHeap.new([5, 6, 7, 8])
188
+ # otherheap = MinHeap.new([1, 2, 3, 4])
189
+ # heap.merge!(otherheap)
190
+ # heap.size #=> 8
191
+ # heap.pop #=> 1
192
+ def merge!(otherheap)
193
+ raise ArgumentError, "Trying to merge a heap with something not a heap" unless otherheap.kind_of? Containers::Heap
194
+ other_root = otherheap.instance_variable_get("@next")
195
+ if other_root
196
+ @stored = @stored.merge(otherheap.instance_variable_get("@stored")) { |key, a, b| (a << b).flatten }
197
+ # Insert othernode's @next node to the left of current @next
198
+ @next.left.right = other_root
199
+ ol = other_root.left
200
+ other_root.left = @next.left
201
+ ol.right = @next
202
+ @next.left = ol
203
+
204
+ @next = other_root if @compare_fn[other_root.key, @next.key]
205
+ end
206
+ @size += otherheap.size
207
+ end
208
+
209
+ # call-seq:
210
+ # pop -> value
211
+ # pop -> nil
212
+ #
213
+ # Returns the value of the next item in heap order and removes it from the heap.
214
+ #
215
+ # Complexity: O(1)
216
+ #
217
+ # minheap = MinHeap.new([1, 2])
218
+ # minheap.pop #=> 1
219
+ # minheap.size #=> 1
220
+ def pop
221
+ return nil unless @next
222
+ popped = @next
223
+ if @size == 1
224
+ clear
225
+ return popped.value
226
+ end
227
+ # Merge the popped's children into root node
228
+ if @next.child
229
+ @next.child.parent = nil
230
+
231
+ # get rid of parent
232
+ sibling = @next.child.right
233
+ until sibling == @next.child
234
+ sibling.parent = nil
235
+ sibling = sibling.right
236
+ end
237
+
238
+ # Merge the children into the root. If @next is the only root node, make its child the @next node
239
+ if @next.right == @next
240
+ @next = @next.child
241
+ else
242
+ next_left, next_right = @next.left, @next.right
243
+ current_child = @next.child
244
+ @next.right.left = current_child
245
+ @next.left.right = current_child.right
246
+ current_child.right.left = next_left
247
+ current_child.right = next_right
248
+ @next = @next.right
249
+ end
250
+ else
251
+ @next.left.right = @next.right
252
+ @next.right.left = @next.left
253
+ @next = @next.right
254
+ end
255
+ consolidate
256
+
257
+ unless @stored[popped.key].delete(popped)
258
+ raise "Couldn't delete node from stored nodes hash"
259
+ end
260
+ @size -= 1
261
+
262
+ popped.value
263
+ end
264
+ alias_method :next!, :pop
265
+
266
+ # call-seq:
267
+ # change_key(key, new_key) -> [new_key, value]
268
+ # change_key(key, new_key) -> nil
269
+ #
270
+ # Changes the key from one to another. Doing so must not violate the heap property or
271
+ # an exception will be raised. If the key is found, an array containing the new key and
272
+ # value pair is returned, otherwise nil is returned.
273
+ #
274
+ # In the case of duplicate keys, an arbitrary key is changed. This will be investigated
275
+ # more in the future.
276
+ #
277
+ # Complexity: amortized O(1)
278
+ #
279
+ # minheap = MinHeap.new([1, 2])
280
+ # minheap.change_key(2, 3) #=> raise error since we can't increase the value in a min-heap
281
+ # minheap.change_key(2, 0) #=> [0, 2]
282
+ # minheap.pop #=> 2
283
+ # minheap.pop #=> 1
284
+ def change_key(key, new_key, delete=false)
285
+ return if @stored[key].nil? || @stored[key].empty? || (key == new_key)
286
+
287
+ # Must maintain heap property
288
+ raise "Changing this key would not maintain heap property!" unless (delete || @compare_fn[new_key, key])
289
+ node = @stored[key].shift
290
+ if node
291
+ node.key = new_key
292
+ @stored[new_key] ||= []
293
+ @stored[new_key] << node
294
+ parent = node.parent
295
+ if parent
296
+ # if heap property is violated
297
+ if delete || @compare_fn[new_key, parent.key]
298
+ cut(node, parent)
299
+ cascading_cut(parent)
300
+ end
301
+ end
302
+ if delete || @compare_fn[node.key, @next.key]
303
+ @next = node
304
+ end
305
+ return [node.key, node.value]
306
+ end
307
+ nil
308
+ end
309
+
310
+ # call-seq:
311
+ # delete(key) -> value
312
+ # delete(key) -> nil
313
+ #
314
+ # Deletes the item with associated key and returns it. nil is returned if the key
315
+ # is not found. In the case of nodes with duplicate keys, an arbitrary one is deleted.
316
+ #
317
+ # Complexity: amortized O(log n)
318
+ #
319
+ # minheap = MinHeap.new([1, 2])
320
+ # minheap.delete(1) #=> 1
321
+ # minheap.size #=> 1
322
+ def delete(key)
323
+ pop if change_key(key, nil, true)
324
+ end
325
+
326
+ # Node class used internally
327
+ class Node # :nodoc:
328
+ attr_accessor :parent, :child, :left, :right, :key, :value, :degree, :marked
329
+
330
+ def initialize(key, value)
331
+ @key = key
332
+ @value = value
333
+ @degree = 0
334
+ @marked = false
335
+ @right = self
336
+ @left = self
337
+ end
338
+
339
+ def marked?
340
+ @marked == true
341
+ end
342
+
343
+ end
344
+
345
+ # make node a child of a parent node
346
+ def link_nodes(child, parent)
347
+ # link the child's siblings
348
+ child.left.right = child.right
349
+ child.right.left = child.left
350
+
351
+ child.parent = parent
352
+
353
+ # if parent doesn't have children, make new child its only child
354
+ if parent.child.nil?
355
+ parent.child = child.right = child.left = child
356
+ else # otherwise insert new child into parent's children list
357
+ current_child = parent.child
358
+ child.left = current_child
359
+ child.right = current_child.right
360
+ current_child.right.left = child
361
+ current_child.right = child
362
+ end
363
+ parent.degree += 1
364
+ child.marked = false
365
+ end
366
+ private :link_nodes
367
+
368
+ # Makes sure the structure does not contain nodes in the root list with equal degrees
369
+ def consolidate
370
+ roots = []
371
+ root = @next
372
+ min = root
373
+ # find the nodes in the list
374
+ loop do
375
+ roots << root
376
+ root = root.right
377
+ break if root == @next
378
+ end
379
+ degrees = []
380
+ roots.each do |root|
381
+ min = root if @compare_fn[root.key, min.key]
382
+ # check if we need to merge
383
+ if degrees[root.degree].nil? # no other node with the same degree
384
+ degrees[root.degree] = root
385
+ next
386
+ else # there is another node with the same degree, consolidate them
387
+ degree = root.degree
388
+ until degrees[degree].nil? do
389
+ other_root_with_degree = degrees[degree]
390
+ if @compare_fn[root.key, other_root_with_degree.key] # determine which node is the parent, which one is the child
391
+ smaller, larger = root, other_root_with_degree
392
+ else
393
+ smaller, larger = other_root_with_degree, root
394
+ end
395
+ link_nodes(larger, smaller)
396
+ degrees[degree] = nil
397
+ root = smaller
398
+ degree += 1
399
+ end
400
+ degrees[degree] = root
401
+ min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
402
+ end
403
+ end
404
+ @next = min
405
+ end
406
+ private :consolidate
407
+
408
+ def cascading_cut(node)
409
+ p = node.parent
410
+ if p
411
+ if node.marked?
412
+ cut(node, p)
413
+ cascading_cut(p)
414
+ else
415
+ node.marked = true
416
+ end
417
+ end
418
+ end
419
+ private :cascading_cut
420
+
421
+ # remove x from y's children and add x to the root list
422
+ def cut(x, y)
423
+ x.left.right = x.right
424
+ x.right.left = x.left
425
+ y.degree -= 1
426
+ if (y.degree == 0)
427
+ y.child = nil
428
+ elsif (y.child == x)
429
+ y.child = x.right
430
+ end
431
+ x.right = @next
432
+ x.left = @next.left
433
+ @next.left = x
434
+ x.left.right = x
435
+ x.parent = nil
436
+ x.marked = false
437
+ end
438
+ private :cut
439
+
440
+ end
441
+
442
+ # A MaxHeap is a heap where the items are returned in descending order of key value.
443
+ class Containers::MaxHeap < Containers::Heap
444
+
445
+ # call-seq:
446
+ # MaxHeap.new(ary) -> new_heap
447
+ #
448
+ # Creates a new MaxHeap with an optional array parameter of items to insert into the heap.
449
+ # A MaxHeap is created by calling Heap.new { |x, y| (x <=> y) == 1 }, so this is a convenience class.
450
+ #
451
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
452
+ # maxheap.pop #=> 4
453
+ # maxheap.pop #=> 3
454
+ def initialize(ary=[])
455
+ super(ary) { |x, y| (x <=> y) == 1 }
456
+ end
457
+
458
+ # call-seq:
459
+ # max -> value
460
+ # max -> nil
461
+ #
462
+ # Returns the item with the largest key, but does not remove it from the heap.
463
+ #
464
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
465
+ # maxheap.max #=> 4
466
+ def max
467
+ self.next
468
+ end
469
+
470
+ # call-seq:
471
+ # max! -> value
472
+ # max! -> nil
473
+ #
474
+ # Returns the item with the largest key and removes it from the heap.
475
+ #
476
+ # maxheap = MaxHeap.new([1, 2, 3, 4])
477
+ # maxheap.max! #=> 4
478
+ # maxheap.size #=> 3
479
+ def max!
480
+ self.pop
481
+ end
482
+ end
483
+
484
+ # A MinHeap is a heap where the items are returned in ascending order of key value.
485
+ class Containers::MinHeap < Containers::Heap
486
+
487
+ # call-seq:
488
+ # MinHeap.new(ary) -> new_heap
489
+ #
490
+ # Creates a new MinHeap with an optional array parameter of items to insert into the heap.
491
+ # A MinHeap is created by calling Heap.new { |x, y| (x <=> y) == -1 }, so this is a convenience class.
492
+ #
493
+ # minheap = MinHeap.new([1, 2, 3, 4])
494
+ # minheap.pop #=> 1
495
+ # minheap.pop #=> 2
496
+ def initialize(ary=[])
497
+ super(ary) { |x, y| (x <=> y) == -1 }
498
+ end
499
+
500
+ # call-seq:
501
+ # min -> value
502
+ # min -> nil
503
+ #
504
+ # Returns the item with the smallest key, but does not remove it from the heap.
505
+ #
506
+ # minheap = MinHeap.new([1, 2, 3, 4])
507
+ # minheap.min #=> 1
508
+ def min
509
+ self.next
510
+ end
511
+
512
+ # call-seq:
513
+ # min! -> value
514
+ # min! -> nil
515
+ #
516
+ # Returns the item with the smallest key and removes it from the heap.
517
+ #
518
+ # minheap = MinHeap.new([1, 2, 3, 4])
519
+ # minheap.min! #=> 1
520
+ # minheap.size #=> 3
521
+ def min!
522
+ self.pop
523
+ end
524
+ end
@@ -0,0 +1,131 @@
1
+ # rdoc
2
+ #
3
+ # A kd-tree is a binary tree that allows one to store points (of any space dimension: 2D, 3D, etc).
4
+ # The structure of the resulting tree makes it so that large portions of the tree are pruned
5
+ # during queries.
6
+ #
7
+ # One very good use of the tree is to allow nearest neighbor searching. Let's say you have a number
8
+ # of points in 2D space, and you want to find the nearest 2 points from a specific point:
9
+ #
10
+ # First, put the points into the tree:
11
+ #
12
+ # kdtree = Containers::KDTree.new( {0 => [4, 3], 1 => [3, 4], 2 => [-1, 2], 3 => [6, 4],
13
+ # 4 => [3, -5], 5 => [-2, -5] })
14
+ #
15
+ # Then, query on the tree:
16
+ #
17
+ # puts kd.find_nearest([0, 0], 2) => [[5, 2], [9, 1]]
18
+ #
19
+ # The result is an array of [distance, id] pairs. There seems to be a bug in this version.
20
+ #
21
+ # Note that the point queried on does not have to exist in the tree. However, if it does exist,
22
+ # it will be returned.
23
+ #
24
+ #
25
+ # MIT License
26
+ #
27
+ # Copyright (c) 2009 Kanwei Li
28
+ #
29
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
30
+ # of this software and associated documentation files (the "Software"), to deal
31
+ # in the Software without restriction, including without limitation the rights
32
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
+ # copies of the Software, and to permit persons to whom the Software is
34
+ # furnished to do so, subject to the following conditions:
35
+ #
36
+ # The above copyright notice and this permission notice shall be included in all
37
+ # copies or substantial portions of the Software.
38
+ #
39
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45
+ # SOFTWARE.
46
+
47
+ class Containers::KDTree
48
+ Node = Struct.new(:id, :coords, :left, :right)
49
+
50
+ # Points is a hash of id => [coord, coord] pairs.
51
+ def initialize(points)
52
+ raise "must pass in a hash" unless points.kind_of?(Hash)
53
+ @dimensions = points[ points.keys.first ].size
54
+ @root = build_tree(points.to_a)
55
+ @nearest = []
56
+ end
57
+
58
+ # Find k closest points to given coordinates
59
+ def find_nearest(target, k_nearest)
60
+ @nearest = []
61
+ nearest(@root, target, k_nearest, 0)
62
+ end
63
+
64
+ # points is an array
65
+ def build_tree(points, depth=0)
66
+ return if points.empty?
67
+
68
+ axis = depth % @dimensions
69
+
70
+ points.sort! { |a, b| a.last[axis] <=> b.last[axis] }
71
+ median = points.size / 2
72
+
73
+ node = Node.new(points[median].first, points[median].last, nil, nil)
74
+ node.left = build_tree(points[0...median], depth+1)
75
+ node.right = build_tree(points[median+1..-1], depth+1)
76
+ node
77
+ end
78
+ private :build_tree
79
+
80
+ # Euclidian distanced, squared, between a node and target coords
81
+ def distance2(node, target)
82
+ return nil if node.nil? or target.nil?
83
+ c = (node.coords[0] - target[0])
84
+ d = (node.coords[1] - target[1])
85
+ c * c + d * d
86
+ end
87
+ private :distance2
88
+
89
+ # Update array of nearest elements if necessary
90
+ def check_nearest(nearest, node, target, k_nearest)
91
+ d = distance2(node, target)
92
+ if nearest.size < k_nearest || d < nearest.last[0]
93
+ nearest.pop if nearest.size >= k_nearest
94
+ nearest << [d, node.id]
95
+ nearest.sort! { |a, b| a[0] <=> b[0] }
96
+ end
97
+ nearest
98
+ end
99
+ private :check_nearest
100
+
101
+ # Recursively find nearest coordinates, going down the appropriate branch as needed
102
+ def nearest(node, target, k_nearest, depth)
103
+ axis = depth % @dimensions
104
+
105
+ if node.left.nil? && node.right.nil? # Leaf node
106
+ @nearest = check_nearest(@nearest, node, target, k_nearest)
107
+ return
108
+ end
109
+
110
+ # Go down the nearest split
111
+ if node.right.nil? || (node.left && target[axis] <= node.coords[axis])
112
+ nearer = node.left
113
+ further = node.right
114
+ else
115
+ nearer = node.right
116
+ further = node.left
117
+ end
118
+ nearest(nearer, target, k_nearest, depth+1)
119
+
120
+ # See if we have to check other side
121
+ if further
122
+ if @nearest.size < k_nearest || (target[axis] - node.coords[axis])**2 < @nearest.last[0]
123
+ nearest(further, target, k_nearest, depth+1)
124
+ end
125
+ end
126
+
127
+ @nearest = check_nearest(@nearest, node, target, k_nearest)
128
+ end
129
+ private :nearest
130
+
131
+ end