algorithms 0.5.0 → 1.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2710897393899fe90ddd5a3046f0fee0dd6d29aec842879ec28654e2767d1626
4
+ data.tar.gz: 8ccc55227d725e590ea965767765c29bb66211866cc948d81a3ed4997d6db733
5
+ SHA512:
6
+ metadata.gz: 8fd77563ddfaecf2ab085f4ff9da6b49e0c63cb65ea666ebf737a3aee175498ddb481908b2135d3ae861ae51f756f9abc9749d27a91d802b4fd8c32965d8a117
7
+ data.tar.gz: d002eba1aa937be5f7afc70e32155dccb108ef5d71cc874729379b403534e34122311234aab35f05c4c1a2df5b0ecfc7fed32b645c2865d1a59b1b911a3564dd
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,11 @@
1
+ === August 20, 2025
2
+
3
+ * Fix Heap not working in certain cases
4
+
5
+ === January 22, 2013
6
+
7
+ * JRuby support
8
+
1
9
  === April 15, 2012
2
10
 
3
11
  * Use long instead of int for string methods
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "rspec"
7
+ gem "rake-compiler"
8
+ end
9
+
data/README.markdown CHANGED
@@ -1,7 +1,6 @@
1
- # algorithms
1
+ # algorithms [![Ruby CI](https://github.com/kanwei/algorithms/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/kanwei/algorithms/actions/workflows/ci.yml)
2
2
 
3
- * Official homes are here on github, and at [rubyforge](http://rubyforge.org/projects/algorithms/)
4
- * Documentation: [http://algorithms.rubyforge.org/](http://algorithms.rubyforge.org/)
3
+ [API Documentation](http://kanwei.github.io/algorithms/)
5
4
 
6
5
  ## DESCRIPTION:
7
6
 
@@ -9,7 +8,9 @@ Started as a [Google Summer of Code 2008](http://code.google.com/soc/2008/ruby/a
9
8
 
10
9
  Written by [Kanwei Li](http://kanwei.com/), mentored by Austin Ziegler
11
10
 
12
- Original Proposal: Using the right data structure or algorithm for the situation is an important
11
+ ## Original Proposal: ##
12
+
13
+ Using the right data structure or algorithm for the situation is an important
13
14
  aspect of programming. In computer science literature, many data structures
14
15
  and algorithms have been researched and extensively documented. However, there
15
16
  is still no standard library in Ruby implementing useful structures and
@@ -18,76 +19,48 @@ This project will create such a library with documentation on when to use a
18
19
  particular structure/algorithm. It will also come with a benchmark suite to
19
20
  compare performance in different situations.
20
21
 
21
- ## FEATURES:
22
-
23
- Done so far:
24
-
25
- * Heaps Containers::Heap, Containers::MaxHeap, Containers::MinHeap
26
- * Priority Queue Containers::PriorityQueue
27
- * Deque Containers::Deque, Containers::CDeque (C extension), Containers::RubyDeque
28
- * Stack Containers::Stack (uses Deque)
29
- * Queue Containers::Queue (uses Deque)
30
- * Red-Black Trees Containers::RBTreeMap, Containers::CRBTreeMap (C extension), Containers::RubyRBTreeMap
31
- * Splay Trees Containers::SplayTreeMap, Containers::CSplayTreeMap (C extension), Containers::RubySplayTreeMap
32
- * Tries Containers::Trie
33
- * Suffix Array Containers::SuffixArray
34
- * kd Tree Containers::KDTree
35
-
36
- * Search algorithms
37
- - Binary Search Algorithms::Search.binary_search
38
- - Knuth-Morris-Pratt Algorithms::Search.kmp_search
39
- * Sort algorithms
40
- - Bubble sort Algorithms::Sort.bubble_sort
41
- - Comb sort Algorithms::Sort.comb_sort
42
- - Selection sort Algorithms::Sort.selection_sort
43
- - Heapsort Algorithms::Sort.heapsort
44
- - Insertion sort Algorithms::Sort.insertion_sort
45
- - Shell sort Algorithms::Sort.shell_sort
46
- - Quicksort Algorithms::Sort.quicksort
47
- - Mergesort Algorithms::Sort.mergesort
22
+ ## COMPLETED:
23
+
24
+ * Heaps Containers::Heap, Containers::MaxHeap, Containers::MinHeap
25
+ * Priority Queue Containers::PriorityQueue
26
+ * Deque Containers::Deque, Containers::CDeque (C ext)
27
+ * Stack Containers::Stack
28
+ * Queue Containers::Queue
29
+ * Red-Black Trees Containers::RBTreeMap, Containers::CRBTreeMap (C ext)
30
+ * Splay Trees Containers::SplayTreeMap, Containers::CSplayTreeMap (C ext)
31
+ * Tries Containers::Trie
32
+ * Suffix Array Containers::SuffixArray
33
+
34
+ * Search algorithms
35
+ - Binary Search Algorithms::Search.binary_search
36
+ - Knuth-Morris-Pratt Algorithms::Search.kmp_search
37
+ * Sorting algorithms
38
+ - Bubble sort Algorithms::Sort.bubble_sort
39
+ - Comb sort Algorithms::Sort.comb_sort
40
+ - Selection sort Algorithms::Sort.selection_sort
41
+ - Heapsort Algorithms::Sort.heapsort
42
+ - Insertion sort Algorithms::Sort.insertion_sort
43
+ - Shell sort Algorithms::Sort.shell_sort
44
+ - Quicksort Algorithms::Sort.quicksort
45
+ - Mergesort Algorithms::Sort.mergesort
46
+ - Dual-Pivot Quicksort Algorithms::Sort.dualpivotquicksort
48
47
 
49
48
  ## SYNOPSIS:
50
49
 
51
- require 'rubygems'
52
- require 'algorithms'
53
-
54
- max_heap = Containers::MaxHeap.new
55
-
56
- # To not have to type "Containers::" before each class, use:
57
- include Containers
58
- max_heap = MaxHeap.new
59
-
50
+ require 'rubygems'
51
+ require 'algorithms'
60
52
 
61
- ## REQUIREMENTS:
53
+ max_heap = Containers::MaxHeap.new
62
54
 
63
- * Ruby 1.8 compatible Ruby, or Ruby 1.9
64
- * C compiler for C extensions (optional, but very much recommended for vast performance benefits)
55
+ # To not have to type "Containers::" before each class, use:
56
+ include Containers
57
+ max_heap = MaxHeap.new
65
58
 
66
- ## INSTALL:
59
+ ## REQUIREMENTS:
67
60
 
68
- * sudo gem install algorithms
61
+ * Ruby 1.8, Ruby 1.9, JRuby
62
+ * C extensions (optional, but very much recommended for vast performance benefits)
69
63
 
70
64
  ## LICENSE:
71
65
 
72
- (The MIT License)
73
-
74
- Algorithms and Containers project is Copyright (c) 2009 Kanwei Li
75
-
76
- Permission is hereby granted, free of charge, to any person obtaining
77
- a copy of this software and associated documentation files (the
78
- 'Software'), to deal in the Software without restriction, including
79
- without limitation the rights to use, copy, modify, merge, publish,
80
- distribute, sublicense, and/or sell copies of the Software, and to
81
- permit persons to whom the Software is furnished to do so, subject to
82
- the following conditions:
83
-
84
- The above copyright notice and this permission notice shall be
85
- included in all copies or substantial portions of the Software.
86
-
87
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
88
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
89
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
90
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
91
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
92
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
93
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66
+ See [LICENSE.md](LICENSE.md).
data/Rakefile CHANGED
@@ -1,13 +1,22 @@
1
1
  require 'rubygems'
2
- require 'echoe'
3
-
4
- Echoe.new('algorithms') do |p|
5
- p.author = 'Kanwei Li'
6
- p.email = 'kanwei@gmail.com'
7
- p.summary = 'A library of algorithms and data structures (containers).'
8
- p.url = 'https://rubygems.org/gems/algorithms'
9
- p.version = "0.5.0"
10
- p.retain_gemspec = true
11
- p.runtime_dependencies = []
12
- p.development_dependencies = ["rspec", "echoe"]
2
+ require 'rake/extensiontask'
3
+ require 'rspec/core/rake_task'
4
+ require 'bundler/gem_tasks'
5
+
6
+ Rake::ExtensionTask.new('algorithms/string') { |ext| ext.name = "CString" }
7
+ Rake::ExtensionTask.new('containers/deque') { |ext| ext.name = "CDeque" }
8
+ Rake::ExtensionTask.new('containers/bst') { |ext| ext.name = "CBst" }
9
+ Rake::ExtensionTask.new('containers/rbtree_map') { |ext| ext.name = "CRBTreeMap" }
10
+ Rake::ExtensionTask.new('containers/splaytree_map') { |ext| ext.name = "CSplayTreeMap" }
11
+
12
+ RSpec::Core::RakeTask.new
13
+
14
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
15
+ task :default => [:spec]
16
+ else
17
+ task :default => [:compile, :spec]
13
18
  end
19
+
20
+ task :rdoc do
21
+ `rdoc -f hanna --main algorithms.rb -t "Ruby Algorithms and Containers Documentation"`
22
+ end
data/algorithms.gemspec CHANGED
@@ -2,35 +2,21 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "algorithms"
5
- s.version = "0.5.0"
5
+ s.version = "1.1.0"
6
6
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
7
  s.authors = ["Kanwei Li"]
9
- s.date = "2012-04-25"
10
- s.description = "A library of algorithms and data structures (containers)."
11
8
  s.email = "kanwei@gmail.com"
12
- s.extensions = ["ext/algorithms/string/extconf.rb", "ext/containers/bst/extconf.rb", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/splaytree_map/extconf.rb"]
13
- s.extra_rdoc_files = ["CHANGELOG.markdown", "README.markdown", "ext/algorithms/string/extconf.rb", "ext/algorithms/string/string.c", "ext/containers/bst/bst.c", "ext/containers/bst/extconf.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "lib/algorithms.rb", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms/string.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb"]
14
- s.files = ["CHANGELOG.markdown", "Manifest", "README.markdown", "Rakefile", "algorithms.gemspec", "benchmarks/deque.rb", "benchmarks/sorts.rb", "benchmarks/treemaps.rb", "ext/algorithms/string/extconf.rb", "ext/algorithms/string/string.c", "ext/containers/bst/bst.c", "ext/containers/bst/extconf.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "lib/algorithms.rb", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms/string.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "spec/bst_gc_mark_spec.rb", "spec/bst_spec.rb", "spec/deque_gc_mark_spec.rb", "spec/deque_spec.rb", "spec/heap_spec.rb", "spec/kd_expected_out.txt", "spec/kd_test_in.txt", "spec/kd_tree_spec.rb", "spec/map_gc_mark_spec.rb", "spec/priority_queue_spec.rb", "spec/queue_spec.rb", "spec/rb_tree_map_spec.rb", "spec/search_spec.rb", "spec/sort_spec.rb", "spec/splay_tree_map_spec.rb", "spec/stack_spec.rb", "spec/string_spec.rb", "spec/suffix_array_spec.rb", "spec/trie_spec.rb"]
15
- s.homepage = "https://rubygems.org/gems/algorithms"
16
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Algorithms", "--main", "README.markdown"]
17
- s.require_paths = ["lib", "ext"]
18
- s.rubyforge_project = "algorithms"
19
- s.rubygems_version = "1.8.15"
20
- s.summary = "A library of algorithms and data structures (containers)."
21
-
22
- if s.respond_to? :specification_version then
23
- s.specification_version = 3
24
-
25
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
- s.add_development_dependency(%q<rspec>, [">= 0"])
27
- s.add_development_dependency(%q<echoe>, [">= 0"])
28
- else
29
- s.add_dependency(%q<rspec>, [">= 0"])
30
- s.add_dependency(%q<echoe>, [">= 0"])
31
- end
9
+ s.license = 'MIT'
10
+ s.date = "2023-11-11"
11
+ s.summary = "Useful algorithms and data structures for Ruby. Optional C extensions."
12
+ s.description = "Heap, Priority Queue, Deque, Stack, Queue, Red-Black Trees, Splay Trees, sorting algorithms, and more"
13
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
14
+ s.platform = "java"
32
15
  else
33
- s.add_dependency(%q<rspec>, [">= 0"])
34
- s.add_dependency(%q<echoe>, [">= 0"])
16
+ s.extensions = ["ext/algorithms/string/extconf.rb", "ext/containers/bst/extconf.rb", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/splaytree_map/extconf.rb"]
35
17
  end
18
+ s.files = ["Gemfile", "CHANGELOG.markdown", "Manifest", "README.markdown", "Rakefile", "algorithms.gemspec", "benchmarks/deque.rb", "benchmarks/sorts.rb", "benchmarks/treemaps.rb", "ext/algorithms/string/extconf.rb", "ext/algorithms/string/string.c", "ext/containers/bst/bst.c", "ext/containers/bst/extconf.rb", "ext/containers/deque/deque.c", "ext/containers/deque/extconf.rb", "ext/containers/rbtree_map/extconf.rb", "ext/containers/rbtree_map/rbtree.c", "ext/containers/splaytree_map/extconf.rb", "ext/containers/splaytree_map/splaytree.c", "lib/algorithms.rb", "lib/algorithms/search.rb", "lib/algorithms/sort.rb", "lib/algorithms/string.rb", "lib/containers/deque.rb", "lib/containers/heap.rb", "lib/containers/kd_tree.rb", "lib/containers/priority_queue.rb", "lib/containers/queue.rb", "lib/containers/rb_tree_map.rb", "lib/containers/splay_tree_map.rb", "lib/containers/stack.rb", "lib/containers/suffix_array.rb", "lib/containers/trie.rb", "spec/bst_gc_mark_spec.rb", "spec/bst_spec.rb", "spec/deque_gc_mark_spec.rb", "spec/deque_spec.rb", "spec/heap_spec.rb", "spec/kd_expected_out.txt", "spec/kd_test_in.txt", "spec/kd_tree_spec.rb", "spec/map_gc_mark_spec.rb", "spec/priority_queue_spec.rb", "spec/queue_spec.rb", "spec/rb_tree_map_spec.rb", "spec/search_spec.rb", "spec/sort_spec.rb", "spec/splay_tree_map_spec.rb", "spec/stack_spec.rb", "spec/string_spec.rb", "spec/suffix_array_spec.rb", "spec/trie_spec.rb"]
19
+ s.homepage = "https://github.com/kanwei/algorithms"
20
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Algorithms", "--main", "README.markdown"]
21
+ s.require_paths = ["lib", "ext"]
36
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 = malloc(sizeof(typeof(d)) * (s1_len) * (s2_len));
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
- free(d);
52
+ xfree(d);
53
53
  return i;
54
54
  }
55
55
 
@@ -172,7 +172,7 @@ static void recursively_free_nodes(bst_node *node) {
172
172
  if(node) {
173
173
  recursively_free_nodes(node->left);
174
174
  recursively_free_nodes(node->right);
175
- free(node);
175
+ xfree(node);
176
176
  }
177
177
  }
178
178
 
@@ -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
- free(node);
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
- free(deque);
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
- free(node);
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
- free(h);
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
- free(h);
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
- free(node);
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
- free(old);
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
- free(tree);
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
- free(node);
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
- free(n);
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
- free(old);
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
- free(tree);
295
+ xfree(tree);
296
296
  }
297
297
  }
298
298
 
@@ -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
+
@@ -5,4 +5,5 @@
5
5
 
6
6
  begin
7
7
  require 'CString'
8
+ rescue LoadError
8
9
  end
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
@@ -10,7 +10,6 @@
10
10
  This library implements a Fibonacci heap, which allows O(1) complexity for most methods.
11
11
  =end
12
12
  class Containers::Heap
13
- include Enumerable
14
13
 
15
14
  # call-seq:
16
15
  # size -> int
@@ -75,13 +74,6 @@ class Containers::Heap
75
74
  end
76
75
  @size += 1
77
76
 
78
- arr = []
79
- w = @next.right
80
- until w == @next do
81
- arr << w.value
82
- w = w.right
83
- end
84
- arr << @next.value
85
77
  @stored[key] ||= []
86
78
  @stored[key] << node
87
79
  value
@@ -376,7 +368,7 @@ class Containers::Heap
376
368
  degree += 1
377
369
  end
378
370
  degrees[degree] = root
379
- min = root if min.key == root.key # this fixes a bug with duplicate keys not being in the right order
371
+ min = root if !@compare_fn[min.key, root.key] # this fixes a bug with duplicate keys not being in the right order
380
372
  end
381
373
  end
382
374
  @next = min
@@ -10,7 +10,6 @@ require 'containers/heap'
10
10
  This container is implemented using the Fibonacci heap included in the Collections library.
11
11
  =end
12
12
  class Containers::PriorityQueue
13
- include Enumerable
14
13
 
15
14
  # Create a new, empty PriorityQueue
16
15
  def initialize(&block)
@@ -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 smallest key and returns the item. Returns nil
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
@@ -13,7 +13,7 @@ class Containers::Trie
13
13
  #
14
14
  # t = Containers::Trie.new
15
15
  # t["hello"] = "world"
16
- # t["hello] #=> "world"
16
+ # t["hello"] #=> "world"
17
17
  def initialize
18
18
  @root = nil
19
19
  end
@@ -12,7 +12,7 @@ if defined? Containers::CDeque
12
12
  # Check if any instances were swept
13
13
  count = 0
14
14
  ObjectSpace.each_object(anon_class) { |x| count += 1 }
15
- count.should eql(100)
15
+ expect(count).to eql(100)
16
16
  end
17
17
  end
18
18
  end