amorim-algorithms 0.6.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.markdown +193 -0
  3. data/Gemfile +9 -0
  4. data/Manifest +51 -0
  5. data/README.markdown +87 -0
  6. data/Rakefile +22 -0
  7. data/algorithms.gemspec +23 -0
  8. data/benchmarks/deque.rb +17 -0
  9. data/benchmarks/sorts.rb +34 -0
  10. data/benchmarks/treemaps.rb +51 -0
  11. data/ext/algorithms/string/extconf.rb +4 -0
  12. data/ext/algorithms/string/string.c +68 -0
  13. data/ext/containers/bst/bst.c +247 -0
  14. data/ext/containers/bst/extconf.rb +4 -0
  15. data/ext/containers/deque/deque.c +247 -0
  16. data/ext/containers/deque/extconf.rb +4 -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/extconf.rb +4 -0
  20. data/ext/containers/splaytree_map/splaytree.c +419 -0
  21. data/lib/algorithms.rb +66 -0
  22. data/lib/algorithms/search.rb +84 -0
  23. data/lib/algorithms/sort.rb +368 -0
  24. data/lib/algorithms/string.rb +9 -0
  25. data/lib/containers/deque.rb +171 -0
  26. data/lib/containers/heap.rb +499 -0
  27. data/lib/containers/kd_tree.rb +110 -0
  28. data/lib/containers/priority_queue.rb +113 -0
  29. data/lib/containers/queue.rb +68 -0
  30. data/lib/containers/rb_tree_map.rb +398 -0
  31. data/lib/containers/splay_tree_map.rb +269 -0
  32. data/lib/containers/stack.rb +67 -0
  33. data/lib/containers/suffix_array.rb +68 -0
  34. data/lib/containers/trie.rb +182 -0
  35. data/spec/bst_gc_mark_spec.rb +25 -0
  36. data/spec/bst_spec.rb +25 -0
  37. data/spec/deque_gc_mark_spec.rb +18 -0
  38. data/spec/deque_spec.rb +108 -0
  39. data/spec/heap_spec.rb +131 -0
  40. data/spec/kd_expected_out.txt +10000 -0
  41. data/spec/kd_test_in.txt +10000 -0
  42. data/spec/kd_tree_spec.rb +34 -0
  43. data/spec/map_gc_mark_spec.rb +29 -0
  44. data/spec/priority_queue_spec.rb +75 -0
  45. data/spec/queue_spec.rb +61 -0
  46. data/spec/rb_tree_map_spec.rb +123 -0
  47. data/spec/search_spec.rb +28 -0
  48. data/spec/sort_spec.rb +29 -0
  49. data/spec/splay_tree_map_spec.rb +106 -0
  50. data/spec/stack_spec.rb +60 -0
  51. data/spec/string_spec.rb +15 -0
  52. data/spec/suffix_array_spec.rb +40 -0
  53. data/spec/trie_spec.rb +59 -0
  54. metadata +108 -0
@@ -0,0 +1,34 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe Containers::KDTree do
5
+ it "should work for a documented example" do
6
+ kdtree = Containers::KDTree.new( {0 => [4, 3], 1 => [3, 0], 2 => [-1, 2], 3 => [6, 4],
7
+ 4 => [3, -5], 5 => [-2, -5] })
8
+ closest_2 = kdtree.find_nearest([0, 0], 2)
9
+ expect(closest_2).to eql([[5, 2], [9, 1]])
10
+ end
11
+
12
+ it "should work for real-life example from facebook puzzle" do
13
+ points = {}
14
+ input = File.open(File.join(File.dirname(__FILE__), 'kd_test_in.txt'), 'r')
15
+
16
+ # Populate points hash
17
+ input.each_line do |line|
18
+ break if line.empty?
19
+ n, x, y = line.split(/\s+/)
20
+ points[n.to_i] = [x.to_f, y.to_f]
21
+ end
22
+
23
+ out = ""
24
+ kdtree = Containers::KDTree.new(points)
25
+ points.sort{ |(k1, v1), (k2, v2)| k1 <=> k2 }.each { |id, point|
26
+ nearest_4 = kdtree.find_nearest(point, 4)
27
+ out << "#{id} #{nearest_4[1..-1].collect{ |n| n[1] }.join(',')}\n"
28
+ }
29
+
30
+ expected = File.read(File.join(File.dirname(__FILE__), 'kd_expected_out.txt'))
31
+ expect(expected).to eql(out)
32
+ end
33
+
34
+ end
@@ -0,0 +1,29 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ if !(defined? RUBY_ENGINE && RUBY_ENGINE == 'jruby')
5
+ describe "map gc mark test" do
6
+ it "should mark ruby object references" do
7
+ anon_key_class = Class.new do
8
+ attr :value
9
+ def initialize(x); @value = x; end
10
+ def <=>(other); value <=> other.value; end
11
+ end
12
+ anon_val_class = Class.new
13
+ @rbtree = Containers::RBTreeMap.new
14
+ @splaytree = Containers::SplayTreeMap.new
15
+ 100.times { |x|
16
+ @rbtree[anon_key_class.new(x)] = anon_val_class.new
17
+ @splaytree[anon_key_class.new(x)] = anon_val_class.new
18
+ }
19
+ # Mark and sweep
20
+ ObjectSpace.garbage_collect
21
+ # Check if any instances were swept
22
+ count = 0
23
+ ObjectSpace.each_object(anon_key_class) { |x| count += 1 }
24
+ expect(count).to eql(200)
25
+ ObjectSpace.each_object(anon_val_class) { |x| count += 1 }
26
+ expect(count).to eql(400)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,75 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe Containers::PriorityQueue do
5
+ before(:each) do
6
+ @q = Containers::PriorityQueue.new
7
+ end
8
+
9
+ describe "(empty priority queue)" do
10
+ it "should return 0 for size and be empty" do
11
+ expect(@q.size).to eql(0)
12
+ expect(@q).to be_empty
13
+ end
14
+
15
+ it "should not return anything" do
16
+ expect(@q.next).to be_nil
17
+ expect(@q.pop).to be_nil
18
+ expect(@q.delete(1)).to be_nil
19
+ expect(@q.has_priority?(1)).to be false
20
+ end
21
+
22
+ it "should give the correct size when adding items" do
23
+ 20.times do |i|
24
+ expect(@q.size).to eql(i)
25
+ @q.push(i, i)
26
+ end
27
+ 10.times do |i|
28
+ expect(@q.size).to eql(20-i)
29
+ @q.pop
30
+ end
31
+ 10.times do |i|
32
+ expect(@q.size).to eql(i+10)
33
+ @q.push(i, i)
34
+ end
35
+ @q.delete(5)
36
+ expect(@q.size).to eql(19)
37
+ end
38
+ end
39
+
40
+ describe "(non-empty priority queue)" do
41
+ before(:each) do
42
+ @q.push("Alaska", 50)
43
+ @q.push("Delaware", 30)
44
+ @q.push("Georgia", 35)
45
+ end
46
+
47
+ it "should next/pop the highest priority" do
48
+ expect(@q.next).to eql("Alaska")
49
+ expect(@q.size).to eql(3)
50
+ expect(@q.pop).to eql("Alaska")
51
+ expect(@q.size).to eql(2)
52
+ end
53
+
54
+ it "should not be empty" do
55
+ expect(@q).not_to be_empty
56
+ end
57
+
58
+ it "should has_priority? priorities it has" do
59
+ expect(@q.has_priority?(50)).to be true
60
+ expect(@q.has_priority?(10)).to be false
61
+ end
62
+
63
+ it "should return nil after popping everything" do
64
+ 3.times do
65
+ @q.pop
66
+ end
67
+ expect(@q.pop).to be_nil
68
+ end
69
+
70
+ it "should delete things it has and not things it doesn't" do
71
+ expect(@q.delete(50)).to eql("Alaska")
72
+ expect(@q.delete(10)).to eql(nil)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,61 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe "empty queue" do
5
+ before(:each) do
6
+ @queue = Containers::Queue.new
7
+ end
8
+
9
+
10
+ it "should return nil when sent #pop" do
11
+ expect(@queue.pop).to be_nil
12
+ end
13
+
14
+ it "should return a size of 1 when sent #push" do
15
+ @queue.push(1)
16
+ expect(@queue.size).to eql(1)
17
+ end
18
+
19
+ it "should return nil when sent #next" do
20
+ expect(@queue.next).to be_nil
21
+ end
22
+
23
+ it "should return empty?" do
24
+ expect(@queue.empty?).to be true
25
+ end
26
+ end
27
+
28
+ describe "non-empty queue" do
29
+ before(:each) do
30
+ @queue = Containers::Queue.new
31
+ @queue.push(10)
32
+ @queue.push("10")
33
+ end
34
+
35
+ it "should return first pushed object" do
36
+ expect(@queue.pop).to eql(10)
37
+ end
38
+
39
+ it "should return the size" do
40
+ expect(@queue.size).to eql(2)
41
+ end
42
+
43
+ it "should not return empty?" do
44
+ expect(@queue.empty?).to be false
45
+ end
46
+
47
+ it "should iterate in FIFO order" do
48
+ arr = []
49
+ @queue.each { |obj| arr << obj }
50
+ expect(arr).to eql([10, "10"])
51
+ end
52
+
53
+ it "should return nil after all gets" do
54
+ 2.times do
55
+ @queue.pop
56
+ end
57
+ expect(@queue.pop).to be_nil
58
+ expect(@queue.next).to be_nil
59
+ end
60
+
61
+ end
@@ -0,0 +1,123 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ shared_examples "empty rbtree" do
5
+ it "should let you push stuff in" do
6
+ 100.times { |x| @tree[x] = x }
7
+ expect(@tree.size).to eql(100)
8
+ end
9
+
10
+ it "should be empty?" do
11
+ expect(@tree.empty?).to be true
12
+ end
13
+
14
+ it "should return 0 for height" do
15
+ expect(@tree.height).to eql(0)
16
+ end
17
+
18
+ it "should return 0 for size" do
19
+ expect(@tree.size).to eql(0)
20
+ end
21
+
22
+ it "should return nil for max and min" do
23
+ expect(@tree.min).to be_nil
24
+ expect(@tree.max).to be_nil
25
+ expect(@tree.min_key).to be_nil
26
+ expect(@tree.max_key).to be_nil
27
+ end
28
+
29
+ it "should not delete" do
30
+ expect(@tree.delete(:non_existing)).to be_nil
31
+ end
32
+ end
33
+
34
+ shared_examples "non-empty rbtree" do
35
+ before(:each) do
36
+ @num_items = 1000
37
+ @random_array = Array.new(@num_items) { rand(@num_items) }
38
+ @random_array.each { |x| @tree[x] = x }
39
+ end
40
+
41
+ it "should return correct size (uniqify items first)" do
42
+ expect(@tree).not_to be_empty
43
+ expect(@tree.size).to eql(@random_array.uniq.size)
44
+ end
45
+
46
+ it "should return correct max and min" do
47
+ expect(@tree.min_key).to eql(@random_array.min)
48
+ expect(@tree.max_key).to eql(@random_array.max)
49
+ expect(@tree.min[0]).to eql(@random_array.min)
50
+ expect(@tree.max[0]).to eql(@random_array.max)
51
+ end
52
+
53
+ it "should not #has_key? keys it doesn't have" do
54
+ expect(@tree.has_key?(100000)).to be false
55
+ end
56
+
57
+ it "should #has_key? keys it does have" do
58
+ expect(@tree.has_key?(@random_array[0])).to be true
59
+ end
60
+
61
+ it "should remove all keys" do
62
+ ordered = []
63
+ @random_array.uniq.each do |key|
64
+ expect(@tree.has_key?(key)).to eql(true)
65
+ ordered << @tree.delete(key)
66
+ expect(@tree.has_key?(key)).to eql(false)
67
+ end
68
+ expect(ordered).to eql(@random_array.uniq)
69
+ end
70
+
71
+ it "should delete_min keys correctly" do
72
+ ascending = []
73
+ ascending << @tree.delete_min until @tree.empty?
74
+ expect(ascending).to eql(@random_array.uniq.sort)
75
+ end
76
+
77
+ it "should delete_max keys correctly" do
78
+ descending = []
79
+ descending << @tree.delete_max until @tree.empty?
80
+ expect(descending).to eql(@random_array.uniq.sort.reverse)
81
+ end
82
+
83
+ it "should let you iterate with #each" do
84
+ counter = 0
85
+ sorted_array = @random_array.uniq.sort
86
+ @tree.each do |key, val|
87
+ expect(key).to eql(sorted_array[counter])
88
+ counter += 1
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "empty rbtreemap" do
94
+ before(:each) do
95
+ @tree = Containers::RubyRBTreeMap.new
96
+ end
97
+ it_should_behave_like "empty rbtree"
98
+ end
99
+
100
+ describe "full rbtreemap" do
101
+ before(:each) do
102
+ @tree = Containers::RubyRBTreeMap.new
103
+ end
104
+ it_should_behave_like "non-empty rbtree"
105
+ end
106
+
107
+ begin
108
+ Containers::CRBTreeMap
109
+ describe "empty crbtreemap" do
110
+ before(:each) do
111
+ @tree = Containers::CRBTreeMap.new
112
+ end
113
+ it_should_behave_like "empty rbtree"
114
+ end
115
+
116
+ describe "full crbtreemap" do
117
+ before(:each) do
118
+ @tree = Containers::CRBTreeMap.new
119
+ end
120
+ it_should_behave_like "non-empty rbtree"
121
+ end
122
+ rescue Exception
123
+ end
@@ -0,0 +1,28 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ class String; include Algorithms::Search; end
5
+
6
+ describe "search algorithms" do
7
+ it "should binary search sorted arrays" do
8
+ n = 1000
9
+ @rand_array = Array.new(n) { rand(n) }.sort
10
+
11
+ expect(Algorithms::Search.binary_search(@rand_array, @rand_array.first)).to eql(@rand_array.first)
12
+ expect(Algorithms::Search.binary_search(@rand_array, 999999)).to be_nil
13
+ expect(Algorithms::Search.binary_search(@rand_array, nil)).to be_nil
14
+ end
15
+
16
+ it "should use kmp_search to find substrings it has" do
17
+ string = "ABC ABCDAB ABCDABCDABDE"
18
+ expect(Algorithms::Search.kmp_search(string, "ABCDABD")).to eql(15)
19
+ expect(Algorithms::Search.kmp_search(string, "ABCDEF")).to be_nil
20
+ expect(Algorithms::Search.kmp_search(string, nil)).to be_nil
21
+ expect(Algorithms::Search.kmp_search(string, "")).to be_nil
22
+ expect(Algorithms::Search.kmp_search(nil, "ABCD")).to be_nil
23
+ end
24
+
25
+ it "should let you include Search in String to enable instance methods" do
26
+ expect("ABC ABCDAB ABCDABCDABDE".kmp_search("ABCDABD")).to eql(15)
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+ include Algorithms
4
+
5
+ describe "sort algorithms" do
6
+ before(:each) do
7
+ @sorts = %w(bubble_sort comb_sort selection_sort heapsort insertion_sort
8
+ shell_sort quicksort mergesort dualpivotquicksort)
9
+ end
10
+
11
+ it "should work for empty containers" do
12
+ empty_array = []
13
+ @sorts.each { |sort| expect(Sort.send(sort, empty_array)).to eql([]) }
14
+ end
15
+
16
+ it "should work for a container of size 1" do
17
+ one_array = [1]
18
+ @sorts.each { |sort| expect(Sort.send(sort, one_array)).to eql([1]) }
19
+ end
20
+
21
+ it "should work for random arrays of numbers" do
22
+ n = 500
23
+ rand_array = Array.new(n) { rand(n) }
24
+ sorted_array = rand_array.sort
25
+
26
+ @sorts.each { |sort| expect(Sort.send(sort, rand_array.dup)).to eql(sorted_array) }
27
+ end
28
+
29
+ end
@@ -0,0 +1,106 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ shared_examples "empty splaytree" do
5
+ it "should let you push stuff in" do
6
+ 100.times { |x| @tree[x] = x }
7
+ expect(@tree.size).to eql(100)
8
+ end
9
+
10
+ it "should return 0 for size" do
11
+ expect(@tree.size).to eql(0)
12
+ end
13
+
14
+ it "should return nil for #min and #max" do
15
+ expect(@tree.min).to be_nil
16
+ expect(@tree.max).to be_nil
17
+ end
18
+
19
+ it "should return nil for #delete" do
20
+ expect(@tree.delete(:non_existing)).to be_nil
21
+ end
22
+
23
+ it "should return nil for #get" do
24
+ expect(@tree[4235]).to be_nil
25
+ end
26
+ end
27
+
28
+ shared_examples "non-empty splaytree" do
29
+ before(:each) do
30
+ @num_items = 100
31
+ @random_array = []
32
+ @num_items.times { @random_array << rand(@num_items) }
33
+ @random_array.each { |x| @tree[x] = x }
34
+ end
35
+
36
+ it "should return correct size (uniqify items first)" do
37
+ expect(@tree.size).to eql(@random_array.uniq.size)
38
+ end
39
+
40
+ it "should have correct height (worst case is when items are inserted in order, and height = num items inserted)" do
41
+ @tree.clear
42
+ 10.times { |x| @tree[x] = x }
43
+ expect(@tree.height).to eql(10)
44
+ end
45
+
46
+ it "should return correct max and min keys" do
47
+ expect(@tree.min[0]).to eql(@random_array.min)
48
+ expect(@tree.max[0]).to eql(@random_array.max)
49
+ end
50
+
51
+ it "should not #has_key? keys it doesn't have" do
52
+ expect(@tree.has_key?(10000)).to be false
53
+ end
54
+
55
+ it "should #has_key? keys it does have" do
56
+ expect(@tree.has_key?(@random_array[0])).to be true
57
+ end
58
+
59
+ it "should remove any key" do
60
+ random_key = @random_array[rand(@num_items)]
61
+ expect(@tree.has_key?(random_key)).to be true
62
+ expect(@tree.delete(random_key)).to eql(random_key)
63
+ expect(@tree.has_key?(random_key)).to be false
64
+ end
65
+
66
+ it "should let you iterate with #each" do
67
+ counter = 0
68
+ sorted_array = @random_array.uniq.sort
69
+ @tree.each do |key, val|
70
+ expect(key).to eql(sorted_array[counter])
71
+ counter += 1
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "empty splaytreemap" do
77
+ before(:each) do
78
+ @tree = Containers::RubySplayTreeMap.new
79
+ end
80
+ it_should_behave_like "empty splaytree"
81
+ end
82
+
83
+ describe "full splaytreemap" do
84
+ before(:each) do
85
+ @tree = Containers::RubySplayTreeMap.new
86
+ end
87
+ it_should_behave_like "non-empty splaytree"
88
+ end
89
+
90
+ begin
91
+ Containers::CSplayTreeMap
92
+ describe "empty csplaytreemap" do
93
+ before(:each) do
94
+ @tree = Containers::CSplayTreeMap.new
95
+ end
96
+ it_should_behave_like "empty splaytree"
97
+ end
98
+
99
+ describe "full csplaytreemap" do
100
+ before(:each) do
101
+ @tree = Containers::CSplayTreeMap.new
102
+ end
103
+ it_should_behave_like "non-empty splaytree"
104
+ end
105
+ rescue Exception
106
+ end