algorithms 0.6.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.markdown +6 -24
- data/Rakefile +4 -0
- data/algorithms.gemspec +2 -3
- data/ext/algorithms/string/string.c +2 -2
- data/ext/containers/bst/bst.c +1 -1
- data/ext/containers/deque/deque.c +2 -2
- data/ext/containers/rbtree_map/rbtree.c +6 -6
- data/ext/containers/splaytree_map/splaytree.c +4 -4
- data/lib/algorithms/sort.rb +130 -0
- data/lib/algorithms.rb +1 -0
- data/lib/containers/heap.rb +0 -7
- data/lib/containers/rb_tree_map.rb +2 -2
- data/lib/containers/suffix_array.rb +3 -3
- data/spec/deque_gc_mark_spec.rb +1 -1
- data/spec/deque_spec.rb +18 -18
- data/spec/heap_spec.rb +25 -25
- data/spec/kd_tree_spec.rb +2 -2
- data/spec/map_gc_mark_spec.rb +2 -2
- data/spec/priority_queue_spec.rb +20 -20
- data/spec/queue_spec.rb +10 -10
- data/spec/rb_tree_map_spec.rb +23 -23
- data/spec/search_spec.rb +9 -9
- data/spec/sort_spec.rb +6 -5
- data/spec/splay_tree_map_spec.rb +16 -16
- data/spec/stack_spec.rb +10 -10
- data/spec/string_spec.rb +6 -6
- data/spec/suffix_array_spec.rb +17 -17
- data/spec/trie_spec.rb +16 -16
- metadata +15 -18
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d542bb52d6a148cc95802bfc5d84549e605b7077009343496e51a00d405bed05
|
4
|
+
data.tar.gz: b66ba40d7c3b4d29f108294e2623f85c48f52f1cdcfa7282191ed412d1877cf5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3bacbfc0793cce5bb67c51b33a64a6a4bb91e0d2cdfea661e5ee5721433bdbc19b723724ebb54e86289b053e71740dcd4c70a7e02fbed998015cd4fa31728f67
|
7
|
+
data.tar.gz: f2ec4934f51e631750aea36af36fb33a4b2dc0fee95ec1b138a8e97c75952b341f9f235e17a12868bb9233e88f6bb4bcfff0800e47fefe417712ee9167d389b1
|
data/README.markdown
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# algorithms [![Build Status](https://travis-ci.org/kanwei/algorithms.
|
1
|
+
# algorithms [![Build Status](https://travis-ci.org/kanwei/algorithms.svg?branch=master)](https://travis-ci.org/github/kanwei/algorithms)
|
2
|
+
|
3
|
+
[API Documentation](http://kanwei.github.io/algorithms/)
|
2
4
|
|
3
5
|
## DESCRIPTION:
|
4
6
|
|
@@ -6,7 +8,7 @@ Started as a [Google Summer of Code 2008](http://code.google.com/soc/2008/ruby/a
|
|
6
8
|
|
7
9
|
Written by [Kanwei Li](http://kanwei.com/), mentored by Austin Ziegler
|
8
10
|
|
9
|
-
|
11
|
+
## Original Proposal: ##
|
10
12
|
|
11
13
|
Using the right data structure or algorithm for the situation is an important
|
12
14
|
aspect of programming. In computer science literature, many data structures
|
@@ -41,6 +43,7 @@ compare performance in different situations.
|
|
41
43
|
- Shell sort Algorithms::Sort.shell_sort
|
42
44
|
- Quicksort Algorithms::Sort.quicksort
|
43
45
|
- Mergesort Algorithms::Sort.mergesort
|
46
|
+
- Dual-Pivot Quicksort Algorithms::Sort.dualpivotquicksort
|
44
47
|
|
45
48
|
## SYNOPSIS:
|
46
49
|
|
@@ -60,25 +63,4 @@ compare performance in different situations.
|
|
60
63
|
|
61
64
|
## LICENSE:
|
62
65
|
|
63
|
-
(
|
64
|
-
|
65
|
-
Ruby Algorithms and Containers project is Copyright (c) 2009 Kanwei Li
|
66
|
-
|
67
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
68
|
-
a copy of this software and associated documentation files (the
|
69
|
-
'Software'), to deal in the Software without restriction, including
|
70
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
71
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
72
|
-
permit persons to whom the Software is furnished to do so, subject to
|
73
|
-
the following conditions:
|
74
|
-
|
75
|
-
The above copyright notice and this permission notice shall be
|
76
|
-
included in all copies or substantial portions of the Software.
|
77
|
-
|
78
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
79
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
80
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
81
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
82
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
83
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
84
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
66
|
+
See [LICENSE.md](LICENSE.md).
|
data/Rakefile
CHANGED
data/algorithms.gemspec
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "algorithms"
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "1.0.1"
|
6
6
|
|
7
7
|
s.authors = ["Kanwei Li"]
|
8
8
|
s.email = "kanwei@gmail.com"
|
9
9
|
s.license = 'MIT'
|
10
|
-
s.date = "
|
10
|
+
s.date = "2023-11-11"
|
11
11
|
s.summary = "Useful algorithms and data structures for Ruby. Optional C extensions."
|
12
12
|
s.description = "Heap, Priority Queue, Deque, Stack, Queue, Red-Black Trees, Splay Trees, sorting algorithms, and more"
|
13
13
|
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
@@ -19,5 +19,4 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.homepage = "https://github.com/kanwei/algorithms"
|
20
20
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Algorithms", "--main", "README.markdown"]
|
21
21
|
s.require_paths = ["lib", "ext"]
|
22
|
-
s.rubyforge_project = "algorithms"
|
23
22
|
end
|
@@ -26,7 +26,7 @@ long levenshtein_distance(VALUE str1, VALUE str2) {
|
|
26
26
|
s1_len++;
|
27
27
|
s2_len++;
|
28
28
|
|
29
|
-
d =
|
29
|
+
d = xmalloc(sizeof(typeof(d)) * s1_len * s2_len);
|
30
30
|
|
31
31
|
for (i = 0; i < s1_len; i++) {
|
32
32
|
d[i] = i; // d[i, 0] = i
|
@@ -49,7 +49,7 @@ long levenshtein_distance(VALUE str1, VALUE str2) {
|
|
49
49
|
}
|
50
50
|
}
|
51
51
|
i = d[s1_len * s2_len -1];
|
52
|
-
|
52
|
+
xfree(d);
|
53
53
|
return i;
|
54
54
|
}
|
55
55
|
|
data/ext/containers/bst/bst.c
CHANGED
@@ -19,7 +19,7 @@ void free_nodes(deque_node *node) {
|
|
19
19
|
deque_node *next;
|
20
20
|
while(node) {
|
21
21
|
next = node->right;
|
22
|
-
|
22
|
+
xfree(node);
|
23
23
|
node = next;
|
24
24
|
}
|
25
25
|
return;
|
@@ -71,7 +71,7 @@ static void deque_free(void *ptr) {
|
|
71
71
|
if (ptr) {
|
72
72
|
deque *deque = ptr;
|
73
73
|
free_nodes(deque->front);
|
74
|
-
|
74
|
+
xfree(deque);
|
75
75
|
}
|
76
76
|
}
|
77
77
|
|
@@ -31,7 +31,7 @@ static void recursively_free_nodes(rbtree_node *node) {
|
|
31
31
|
if(node) {
|
32
32
|
recursively_free_nodes(node->left);
|
33
33
|
recursively_free_nodes(node->right);
|
34
|
-
|
34
|
+
xfree(node);
|
35
35
|
}
|
36
36
|
return;
|
37
37
|
}
|
@@ -198,7 +198,7 @@ static rbtree_node* delete_min(rbtree_node *h, VALUE *deleted_value) {
|
|
198
198
|
if ( !h->left ) {
|
199
199
|
if(deleted_value)
|
200
200
|
*deleted_value = h->value;
|
201
|
-
|
201
|
+
xfree(h);
|
202
202
|
return NULL;
|
203
203
|
}
|
204
204
|
|
@@ -216,7 +216,7 @@ static rbtree_node* delete_max(rbtree_node *h, VALUE *deleted_value) {
|
|
216
216
|
|
217
217
|
if ( !h->right ) {
|
218
218
|
*deleted_value = h->value;
|
219
|
-
|
219
|
+
xfree(h);
|
220
220
|
return NULL;
|
221
221
|
}
|
222
222
|
|
@@ -245,7 +245,7 @@ static rbtree_node* delete(rbtree *tree, rbtree_node *node, VALUE key, VALUE *de
|
|
245
245
|
cmp = tree->compare_function(key, node->key);
|
246
246
|
if ( (cmp == 0) && !node->right ) {
|
247
247
|
*deleted_value = node->value;
|
248
|
-
|
248
|
+
xfree(node);
|
249
249
|
return NULL;
|
250
250
|
}
|
251
251
|
|
@@ -339,7 +339,7 @@ static void rbtree_mark(void *ptr) {
|
|
339
339
|
}
|
340
340
|
old = current;
|
341
341
|
current = current->next;
|
342
|
-
|
342
|
+
xfree(old);
|
343
343
|
}
|
344
344
|
}
|
345
345
|
}
|
@@ -349,7 +349,7 @@ static void rbtree_free(void *ptr) {
|
|
349
349
|
if (ptr) {
|
350
350
|
rbtree *tree = ptr;
|
351
351
|
recursively_free_nodes(tree->root);
|
352
|
-
|
352
|
+
xfree(tree);
|
353
353
|
}
|
354
354
|
}
|
355
355
|
|
@@ -28,7 +28,7 @@ static void recursively_free_nodes(splaytree_node *node) {
|
|
28
28
|
if(node) {
|
29
29
|
recursively_free_nodes(node->left);
|
30
30
|
recursively_free_nodes(node->right);
|
31
|
-
|
31
|
+
xfree(node);
|
32
32
|
}
|
33
33
|
return;
|
34
34
|
}
|
@@ -199,7 +199,7 @@ static splaytree_node* delete(splaytree *tree, splaytree_node *n, VALUE key, VAL
|
|
199
199
|
x = splay(tree, n->left, key);
|
200
200
|
x->right = n->right;
|
201
201
|
}
|
202
|
-
|
202
|
+
xfree(n);
|
203
203
|
if (x) {
|
204
204
|
x->size = tsize-1;
|
205
205
|
}
|
@@ -282,7 +282,7 @@ static void splaytree_mark(void *ptr) {
|
|
282
282
|
}
|
283
283
|
old = current;
|
284
284
|
current = current->next;
|
285
|
-
|
285
|
+
xfree(old);
|
286
286
|
}
|
287
287
|
}
|
288
288
|
}
|
@@ -292,7 +292,7 @@ static void splaytree_free(void *ptr) {
|
|
292
292
|
if (ptr) {
|
293
293
|
splaytree *tree = ptr;
|
294
294
|
recursively_free_nodes(tree->root);
|
295
|
-
|
295
|
+
xfree(tree);
|
296
296
|
}
|
297
297
|
}
|
298
298
|
|
data/lib/algorithms/sort.rb
CHANGED
@@ -235,4 +235,134 @@ module Algorithms::Sort
|
|
235
235
|
sorted + left + right
|
236
236
|
end
|
237
237
|
|
238
|
+
# Dual-Pivot Quicksort is a variation of Quicksort by Vladimir Yaroslavskiy.
|
239
|
+
# This is an implementation of the algorithm as it was found in the original
|
240
|
+
# research paper:
|
241
|
+
#
|
242
|
+
# http://iaroslavski.narod.ru/quicksort/DualPivotQuicksort.pdf
|
243
|
+
#
|
244
|
+
# Mirror:
|
245
|
+
# http://codeblab.com/wp-content/uploads/2009/09/DualPivotQuicksort.pdf
|
246
|
+
#
|
247
|
+
# "This algorithm offers O(n log(n)) performance on many data sets that cause
|
248
|
+
# other quicksorts to degrade to quadratic performance, and is typically
|
249
|
+
# faster than traditional (one-pivot) Quicksort implementations."
|
250
|
+
# -- http://download.oracle.com/javase/7/docs/api/java/util/Arrays.html
|
251
|
+
#
|
252
|
+
# The algorithm was improved by Vladimir Yaroslavskiy, Jon Bentley, and
|
253
|
+
# Joshua Bloch, and was implemented as the default sort algorithm for
|
254
|
+
# primatives in Java 7.
|
255
|
+
#
|
256
|
+
# Implementation in the Java JDK as of November, 2011:
|
257
|
+
# http://www.docjar.com/html/api/java/util/DualPivotQuicksort.java.html
|
258
|
+
#
|
259
|
+
# It is proved that for the Dual-Pivot Quicksort the average number
|
260
|
+
# of comparisons is 2*n*ln(n), the average number of swaps is
|
261
|
+
# 0.8*n*ln(n), whereas classical Quicksort algorithm has 2*n*ln(n)
|
262
|
+
# and 1*n*ln(n) respectively. This has been fully examined mathematically
|
263
|
+
# and experimentally.
|
264
|
+
#
|
265
|
+
# Requirements: Container should implement #pop and include the Enumerable module.
|
266
|
+
# Time Complexity: О(n log n) average, О(n log n) worst-case
|
267
|
+
# Space Complexity: О(n) auxiliary
|
268
|
+
#
|
269
|
+
# Stable: No
|
270
|
+
#
|
271
|
+
# Algorithms::Sort.dualpivotquicksort [5, 4, 3, 1, 2] => [1, 2, 3, 4, 5]
|
272
|
+
|
273
|
+
def self.dualpivotquicksort(container)
|
274
|
+
return container if container.size <= 1
|
275
|
+
dualpivot(container, 0, container.size-1, 3)
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.dualpivot(container, left=0, right=container.size-1, div=3)
|
279
|
+
length = right - left
|
280
|
+
if length < 27 # insertion sort for tiny array
|
281
|
+
container.each_with_index do |data,i|
|
282
|
+
j = i - 1
|
283
|
+
while j >= 0
|
284
|
+
break if container[j] <= data
|
285
|
+
container[j + 1] = container[j]
|
286
|
+
j = j - 1
|
287
|
+
end
|
288
|
+
container[j + 1] = data
|
289
|
+
end
|
290
|
+
else # full dual-pivot quicksort
|
291
|
+
third = length / div
|
292
|
+
# medians
|
293
|
+
m1 = left + third
|
294
|
+
m2 = right - third
|
295
|
+
if m1 <= left
|
296
|
+
m1 = left + 1
|
297
|
+
end
|
298
|
+
if m2 >= right
|
299
|
+
m2 = right - 1
|
300
|
+
end
|
301
|
+
if container[m1] < container[m2]
|
302
|
+
dualpivot_swap(container, m1, left)
|
303
|
+
dualpivot_swap(container, m2, right)
|
304
|
+
else
|
305
|
+
dualpivot_swap(container, m1, right)
|
306
|
+
dualpivot_swap(container, m2, left)
|
307
|
+
end
|
308
|
+
# pivots
|
309
|
+
pivot1 = container[left]
|
310
|
+
pivot2 = container[right]
|
311
|
+
# pointers
|
312
|
+
less = left + 1
|
313
|
+
great = right - 1
|
314
|
+
# sorting
|
315
|
+
k = less
|
316
|
+
while k <= great
|
317
|
+
if container[k] < pivot1
|
318
|
+
dualpivot_swap(container, k, less += 1)
|
319
|
+
elsif container[k] > pivot2
|
320
|
+
while k < great && container[great] > pivot2
|
321
|
+
great -= 1
|
322
|
+
end
|
323
|
+
dualpivot_swap(container, k, great -= 1)
|
324
|
+
if container[k] < pivot1
|
325
|
+
dualpivot_swap(container, k, less += 1)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
k += 1
|
329
|
+
end
|
330
|
+
# swaps
|
331
|
+
dist = great - less
|
332
|
+
if dist < 13
|
333
|
+
div += 1
|
334
|
+
end
|
335
|
+
dualpivot_swap(container, less-1, left)
|
336
|
+
dualpivot_swap(container, great+1, right)
|
337
|
+
# subarrays
|
338
|
+
dualpivot(container, left, less-2, div)
|
339
|
+
dualpivot(container, great+2, right, div)
|
340
|
+
# equal elements
|
341
|
+
if dist > length - 13 && pivot1 != pivot2
|
342
|
+
for k in less..great do
|
343
|
+
if container[k] == pivot1
|
344
|
+
dualpivot_swap(container, k, less)
|
345
|
+
less += 1
|
346
|
+
elsif container[k] == pivot2
|
347
|
+
dualpivot_swap(container, k, great)
|
348
|
+
great -= 1
|
349
|
+
if container[k] == pivot1
|
350
|
+
dualpivot_swap(container, k, less)
|
351
|
+
less += 1
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
# subarray
|
357
|
+
if pivot1 < pivot2
|
358
|
+
dualpivot(container, less, great, div)
|
359
|
+
end
|
360
|
+
container
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def self.dualpivot_swap(container, i, j)
|
365
|
+
container[i], container[j] = container[j], container[i]
|
366
|
+
end
|
238
367
|
end
|
368
|
+
|
data/lib/algorithms.rb
CHANGED
@@ -43,6 +43,7 @@
|
|
43
43
|
- Shell sort - Algorithms::Sort.shell_sort
|
44
44
|
- Quicksort - Algorithms::Sort.quicksort
|
45
45
|
- Mergesort - Algorithms::Sort.mergesort
|
46
|
+
- Dual-Pivot Quicksort - Algorithms::Sort.dualpivotquicksort
|
46
47
|
* String algorithms
|
47
48
|
- Levenshtein distance - Algorithms::String.levenshtein_dist
|
48
49
|
=end
|
data/lib/containers/heap.rb
CHANGED
@@ -15,7 +15,7 @@ require 'containers/stack'
|
|
15
15
|
explicitly used as well; their functionality is identical.
|
16
16
|
|
17
17
|
Most methods have O(log n) complexity.
|
18
|
-
|
18
|
+
|
19
19
|
=end
|
20
20
|
class Containers::RubyRBTreeMap
|
21
21
|
include Enumerable
|
@@ -160,7 +160,7 @@ class Containers::RubyRBTreeMap
|
|
160
160
|
result
|
161
161
|
end
|
162
162
|
|
163
|
-
# Deletes the item with the
|
163
|
+
# Deletes the item with the largest key and returns the item. Returns nil
|
164
164
|
# if key is not present.
|
165
165
|
#
|
166
166
|
# Complexity: O(log n)
|
@@ -12,10 +12,10 @@ class Containers::SuffixArray
|
|
12
12
|
#
|
13
13
|
# Complexity: O(n^2 log n)
|
14
14
|
#
|
15
|
-
# s_array = Containers::SuffixArray("abracadabra")
|
15
|
+
# s_array = Containers::SuffixArray.new("abracadabra")
|
16
16
|
# s_array["abra"] #=> true
|
17
17
|
#
|
18
|
-
# number = Containers::SuffixArray(1234567)
|
18
|
+
# number = Containers::SuffixArray.new(1234567)
|
19
19
|
# number[1] #=> true
|
20
20
|
# number[13] #=> false
|
21
21
|
def initialize(string)
|
@@ -65,4 +65,4 @@ class Containers::SuffixArray
|
|
65
65
|
return false
|
66
66
|
end
|
67
67
|
alias_method :[], :has_substring?
|
68
|
-
end
|
68
|
+
end
|
data/spec/deque_gc_mark_spec.rb
CHANGED
data/spec/deque_spec.rb
CHANGED
@@ -3,31 +3,31 @@ require 'algorithms'
|
|
3
3
|
|
4
4
|
shared_examples "(empty deque)" do
|
5
5
|
it "should return nil when popping objects" do
|
6
|
-
@deque.pop_front.
|
7
|
-
@deque.pop_back.
|
6
|
+
expect(@deque.pop_front).to be_nil
|
7
|
+
expect(@deque.pop_back).to be_nil
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should return a size of 1 when sent #push_front" do
|
11
11
|
@deque.push_front(1)
|
12
|
-
@deque.size.
|
12
|
+
expect(@deque.size).to eql(1)
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should return a size of 1 when sent #push_back" do
|
16
16
|
@deque.push_back(1)
|
17
|
-
@deque.size.
|
17
|
+
expect(@deque.size).to eql(1)
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should return nil when sent #front and #back" do
|
21
|
-
@deque.front.
|
22
|
-
@deque.back.
|
21
|
+
expect(@deque.front).to be_nil
|
22
|
+
expect(@deque.back).to be_nil
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should be empty" do
|
26
|
-
@deque.
|
26
|
+
expect(@deque).to be_empty
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should raise ArgumentError if passed more than one argument" do
|
30
|
-
|
30
|
+
expect { @deque.class.send("new", Time.now, []) }.to raise_error(ArgumentError)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -38,40 +38,40 @@ shared_examples "(non-empty deque)" do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should return last pushed object with pop_back" do
|
41
|
-
@deque.pop_back.
|
42
|
-
@deque.pop_back.
|
41
|
+
expect(@deque.pop_back).to eql("10")
|
42
|
+
expect(@deque.pop_back).to eql(10)
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should return first pushed object with pop_front" do
|
46
|
-
@deque.pop_front.
|
47
|
-
@deque.pop_front.
|
46
|
+
expect(@deque.pop_front).to eql(10)
|
47
|
+
expect(@deque.pop_front).to eql("10")
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should return a size greater than 0" do
|
51
|
-
@deque.size.
|
51
|
+
expect(@deque.size).to eql(2)
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should not be empty" do
|
55
|
-
@deque.
|
55
|
+
expect(@deque).not_to be_empty
|
56
56
|
end
|
57
57
|
|
58
58
|
it "should iterate in LIFO order with #each_backward" do
|
59
59
|
arr = []
|
60
60
|
@deque.each_backward { |obj| arr << obj }
|
61
|
-
arr.
|
61
|
+
expect(arr).to eql(["10", 10])
|
62
62
|
end
|
63
63
|
|
64
64
|
it "should iterate in FIFO order with #each_forward" do
|
65
65
|
arr = []
|
66
66
|
@deque.each_forward { |obj| arr << obj }
|
67
|
-
arr.
|
67
|
+
expect(arr).to eql([10, "10"])
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should return nil after everything's popped" do
|
71
71
|
@deque.pop_back
|
72
72
|
@deque.pop_back
|
73
|
-
@deque.pop_back.
|
74
|
-
@deque.front.
|
73
|
+
expect(@deque.pop_back).to be_nil
|
74
|
+
expect(@deque.front).to be_nil
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
data/spec/heap_spec.rb
CHANGED
@@ -7,29 +7,29 @@ describe Containers::Heap do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should not let you merge with non-heaps" do
|
10
|
-
|
11
|
-
|
10
|
+
expect { @heap.merge!(nil) }.to raise_error(ArgumentError)
|
11
|
+
expect { @heap.merge!([]) }.to raise_error(ArgumentError)
|
12
12
|
end
|
13
13
|
|
14
14
|
describe "(empty)" do
|
15
15
|
|
16
16
|
it "should return nil when getting the maximum" do
|
17
|
-
@heap.max
|
17
|
+
expect(@heap.max!).to be_nil
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should let you insert and remove one item" do
|
21
|
-
@heap.size.
|
21
|
+
expect(@heap.size).to eql(0)
|
22
22
|
|
23
23
|
@heap.push(1)
|
24
|
-
@heap.size.
|
24
|
+
expect(@heap.size).to eql(1)
|
25
25
|
|
26
|
-
@heap.max
|
27
|
-
@heap.size.
|
26
|
+
expect(@heap.max!).to eql(1)
|
27
|
+
expect(@heap.size).to eql(0)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should let you initialize with an array" do
|
31
31
|
@heap = Containers::MaxHeap.new([1,2,3])
|
32
|
-
@heap.size.
|
32
|
+
expect(@heap.size).to eql(3)
|
33
33
|
end
|
34
34
|
|
35
35
|
end
|
@@ -38,25 +38,25 @@ describe Containers::Heap do
|
|
38
38
|
before(:each) do
|
39
39
|
@random_array = []
|
40
40
|
@num_items = 100
|
41
|
-
@num_items.times {
|
41
|
+
@num_items.times { @random_array << rand(@num_items) }
|
42
42
|
@heap = Containers::MaxHeap.new(@random_array)
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should display the correct size" do
|
46
|
-
@heap.size.
|
46
|
+
expect(@heap.size).to eql(@num_items)
|
47
47
|
end
|
48
48
|
|
49
49
|
it "should have a next value" do
|
50
|
-
@heap.next.
|
51
|
-
@heap.next_key.
|
50
|
+
expect(@heap.next).to be_truthy
|
51
|
+
expect(@heap.next_key).to be_truthy
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should delete random keys" do
|
55
|
-
@heap.delete(@random_array[0]).
|
56
|
-
@heap.delete(@random_array[1]).
|
55
|
+
expect(@heap.delete(@random_array[0])).to eql(@random_array[0])
|
56
|
+
expect(@heap.delete(@random_array[1])).to eql(@random_array[1])
|
57
57
|
ordered = []
|
58
58
|
ordered << @heap.max! until @heap.empty?
|
59
|
-
ordered.
|
59
|
+
expect(ordered).to eql( @random_array[2..-1].sort.reverse )
|
60
60
|
end
|
61
61
|
|
62
62
|
it "should delete all keys" do
|
@@ -64,15 +64,15 @@ describe Containers::Heap do
|
|
64
64
|
@random_array.size.times do |t|
|
65
65
|
ordered << @heap.delete(@random_array[t])
|
66
66
|
end
|
67
|
-
@heap.
|
68
|
-
ordered.
|
67
|
+
expect(@heap).to be_empty
|
68
|
+
expect(ordered).to eql( @random_array )
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should be in max->min order" do
|
72
72
|
ordered = []
|
73
73
|
ordered << @heap.max! until @heap.empty?
|
74
74
|
|
75
|
-
ordered.
|
75
|
+
expect(ordered).to eql(@random_array.sort.reverse)
|
76
76
|
end
|
77
77
|
|
78
78
|
it "should change certain keys" do
|
@@ -84,12 +84,12 @@ describe Containers::Heap do
|
|
84
84
|
heap.change_key(8, 0)
|
85
85
|
ordered = []
|
86
86
|
ordered << heap.min! until heap.empty?
|
87
|
-
ordered.
|
87
|
+
expect(ordered).to eql( [8,3,4,5,6,7,9,10,101,100] )
|
88
88
|
end
|
89
89
|
|
90
90
|
it "should not delete keys it doesn't have" do
|
91
|
-
@heap.delete(:nonexisting).
|
92
|
-
@heap.size.
|
91
|
+
expect(@heap.delete(:nonexisting)).to be_nil
|
92
|
+
expect(@heap.size).to eql(@num_items)
|
93
93
|
end
|
94
94
|
|
95
95
|
it "should delete certain keys" do
|
@@ -101,19 +101,19 @@ describe Containers::Heap do
|
|
101
101
|
heap.delete(100)
|
102
102
|
ordered = []
|
103
103
|
ordered << heap.min! until heap.empty?
|
104
|
-
ordered.
|
104
|
+
expect(ordered).to eql( [3,4,6,7,8,9,10,101] )
|
105
105
|
end
|
106
106
|
|
107
107
|
it "should let you merge with another heap" do
|
108
108
|
numbers = [1,2,3,4,5,6,7,8]
|
109
109
|
otherheap = Containers::MaxHeap.new(numbers)
|
110
|
-
otherheap.size.
|
110
|
+
expect(otherheap.size).to eql(8)
|
111
111
|
@heap.merge!(otherheap)
|
112
112
|
|
113
113
|
ordered = []
|
114
114
|
ordered << @heap.max! until @heap.empty?
|
115
115
|
|
116
|
-
ordered.
|
116
|
+
expect(ordered).to eql( (@random_array + numbers).sort.reverse)
|
117
117
|
end
|
118
118
|
|
119
119
|
describe "min-heap" do
|
@@ -122,7 +122,7 @@ describe Containers::Heap do
|
|
122
122
|
ordered = []
|
123
123
|
ordered << @heap.min! until @heap.empty?
|
124
124
|
|
125
|
-
ordered.
|
125
|
+
expect(ordered).to eql(@random_array.sort)
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
data/spec/kd_tree_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Containers::KDTree do
|
|
6
6
|
kdtree = Containers::KDTree.new( {0 => [4, 3], 1 => [3, 0], 2 => [-1, 2], 3 => [6, 4],
|
7
7
|
4 => [3, -5], 5 => [-2, -5] })
|
8
8
|
closest_2 = kdtree.find_nearest([0, 0], 2)
|
9
|
-
closest_2.
|
9
|
+
expect(closest_2).to eql([[5, 2], [9, 1]])
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should work for real-life example from facebook puzzle" do
|
@@ -28,7 +28,7 @@ describe Containers::KDTree do
|
|
28
28
|
}
|
29
29
|
|
30
30
|
expected = File.read(File.join(File.dirname(__FILE__), 'kd_expected_out.txt'))
|
31
|
-
expected.
|
31
|
+
expect(expected).to eql(out)
|
32
32
|
end
|
33
33
|
|
34
34
|
end
|