kanwei-algorithms 0.2.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.
Files changed (42) hide show
  1. data/History.txt +168 -0
  2. data/Manifest +41 -0
  3. data/README.markdown +92 -0
  4. data/Rakefile +31 -0
  5. data/algorithms.gemspec +32 -0
  6. data/benchmarks/deque.rb +17 -0
  7. data/benchmarks/sorts.rb +34 -0
  8. data/benchmarks/treemaps.rb +36 -0
  9. data/ext/containers/deque/deque.c +247 -0
  10. data/ext/containers/deque/extconf.rb +4 -0
  11. data/ext/containers/rbtree_map/extconf.rb +4 -0
  12. data/ext/containers/rbtree_map/rbtree.c +473 -0
  13. data/ext/containers/splaytree_map/extconf.rb +4 -0
  14. data/ext/containers/splaytree_map/splaytree.c +370 -0
  15. data/lib/algorithms/search.rb +84 -0
  16. data/lib/algorithms/sort.rb +238 -0
  17. data/lib/algorithms.rb +67 -0
  18. data/lib/containers/deque.rb +171 -0
  19. data/lib/containers/heap.rb +486 -0
  20. data/lib/containers/kd_tree.rb +87 -0
  21. data/lib/containers/priority_queue.rb +113 -0
  22. data/lib/containers/queue.rb +68 -0
  23. data/lib/containers/rb_tree_map.rb +398 -0
  24. data/lib/containers/splay_tree_map.rb +269 -0
  25. data/lib/containers/stack.rb +67 -0
  26. data/lib/containers/suffix_array.rb +68 -0
  27. data/lib/containers/trie.rb +182 -0
  28. data/spec/deque_gc_mark_spec.rb +18 -0
  29. data/spec/deque_spec.rb +108 -0
  30. data/spec/heap_spec.rb +126 -0
  31. data/spec/kd_tree_spec.rb +4 -0
  32. data/spec/priority_queue_spec.rb +75 -0
  33. data/spec/queue_spec.rb +61 -0
  34. data/spec/rb_tree_map_gc_mark_spec.rb +25 -0
  35. data/spec/rb_tree_map_spec.rb +123 -0
  36. data/spec/search_spec.rb +28 -0
  37. data/spec/sort_spec.rb +28 -0
  38. data/spec/splay_tree_map_spec.rb +102 -0
  39. data/spec/stack_spec.rb +60 -0
  40. data/spec/suffix_array_spec.rb +40 -0
  41. data/spec/trie_spec.rb +59 -0
  42. metadata +120 -0
@@ -0,0 +1,18 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ if defined? Containers::CDeque
5
+ describe "CDeque" do
6
+ it "should mark ruby object references" do
7
+ anon_class = Class.new
8
+ @deque = Containers::CDeque.new
9
+ 100.times { @deque.push_front(anon_class.new) }
10
+ # Mark and sweep
11
+ ObjectSpace.garbage_collect
12
+ # Check if any instances were swept
13
+ count = 0
14
+ ObjectSpace.each_object(anon_class) { |x| count += 1 }
15
+ count.should eql(100)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,108 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe "(empty deque)", :shared => true do
5
+ it "should return nil when popping objects" do
6
+ @deque.pop_front.should be_nil
7
+ @deque.pop_back.should be_nil
8
+ end
9
+
10
+ it "should return a size of 1 when sent #push_front" do
11
+ @deque.push_front(1)
12
+ @deque.size.should eql(1)
13
+ end
14
+
15
+ it "should return a size of 1 when sent #push_back" do
16
+ @deque.push_back(1)
17
+ @deque.size.should eql(1)
18
+ end
19
+
20
+ it "should return nil when sent #front and #back" do
21
+ @deque.front.should be_nil
22
+ @deque.back.should be_nil
23
+ end
24
+
25
+ it "should be empty" do
26
+ @deque.should be_empty
27
+ end
28
+
29
+ it "should raise ArgumentError if passed more than one argument" do
30
+ lambda { @deque.class.send("new", Time.now, []) }.should raise_error
31
+ end
32
+ end
33
+
34
+ describe "(non-empty deque)", :shared => true do
35
+ before(:each) do
36
+ @deque.push_back(10)
37
+ @deque.push_back("10")
38
+ end
39
+
40
+ it "should return last pushed object with pop_back" do
41
+ @deque.pop_back.should eql("10")
42
+ @deque.pop_back.should eql(10)
43
+ end
44
+
45
+ it "should return first pushed object with pop_front" do
46
+ @deque.pop_front.should eql(10)
47
+ @deque.pop_front.should eql("10")
48
+ end
49
+
50
+ it "should return a size greater than 0" do
51
+ @deque.size.should eql(2)
52
+ end
53
+
54
+ it "should not be empty" do
55
+ @deque.should_not be_empty
56
+ end
57
+
58
+ it "should iterate in LIFO order with #each_backward" do
59
+ arr = []
60
+ @deque.each_backward { |obj| arr << obj }
61
+ arr.should eql(["10", 10])
62
+ end
63
+
64
+ it "should iterate in FIFO order with #each_forward" do
65
+ arr = []
66
+ @deque.each_forward { |obj| arr << obj }
67
+ arr.should eql([10, "10"])
68
+ end
69
+
70
+ it "should return nil after everything's popped" do
71
+ @deque.pop_back
72
+ @deque.pop_back
73
+ @deque.pop_back.should be_nil
74
+ @deque.front.should be_nil
75
+ end
76
+ end
77
+
78
+ describe "empty rubydeque" do
79
+ before(:each) do
80
+ @deque = Containers::RubyDeque.new
81
+ end
82
+ it_should_behave_like "(empty deque)"
83
+ end
84
+
85
+ describe "full rubydeque" do
86
+ before(:each) do
87
+ @deque = Containers::RubyDeque.new
88
+ end
89
+ it_should_behave_like "(non-empty deque)"
90
+ end
91
+
92
+ begin
93
+ Containers::CDeque
94
+ describe "empty cdeque" do
95
+ before(:each) do
96
+ @deque = Containers::CDeque.new
97
+ end
98
+ it_should_behave_like "(empty deque)"
99
+ end
100
+
101
+ describe "full cdeque" do
102
+ before(:each) do
103
+ @deque = Containers::CDeque.new
104
+ end
105
+ it_should_behave_like "(non-empty deque)"
106
+ end
107
+ rescue Exception
108
+ end
data/spec/heap_spec.rb ADDED
@@ -0,0 +1,126 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe Containers::Heap do
5
+ before(:each) do
6
+ @heap = Containers::MaxHeap.new
7
+ end
8
+
9
+ it "should not let you merge with non-heaps" do
10
+ lambda { @heap.merge!(nil) }.should raise_error
11
+ lambda { @heap.merge!([]) }.should raise_error
12
+ end
13
+
14
+ describe "(empty)" do
15
+
16
+ it "should return nil when getting the maximum" do
17
+ @heap.max!.should be_nil
18
+ end
19
+
20
+ it "should let you insert and remove one item" do
21
+ @heap.size.should eql(0)
22
+
23
+ @heap.push(1)
24
+ @heap.size.should eql(1)
25
+
26
+ @heap.max!.should eql(1)
27
+ @heap.size.should eql(0)
28
+ end
29
+
30
+ it "should let you initialize with an array" do
31
+ @heap = Containers::MaxHeap.new([1,2,3])
32
+ @heap.size.should eql(3)
33
+ end
34
+
35
+ end
36
+
37
+ describe "(non-empty)" do
38
+ before(:each) do
39
+ @random_array = []
40
+ @num_items = 100
41
+ @num_items.times { |x| @random_array << rand(@num_items) }
42
+ @heap = Containers::MaxHeap.new(@random_array)
43
+ end
44
+
45
+ it "should display the correct size" do
46
+ @heap.size.should eql(@num_items)
47
+ end
48
+
49
+ it "should delete random keys" do
50
+ @heap.delete(@random_array[0]).should eql(@random_array[0])
51
+ @heap.delete(@random_array[1]).should eql(@random_array[1])
52
+ ordered = []
53
+ ordered << @heap.max! until @heap.empty?
54
+ ordered.should eql( @random_array[2..-1].sort.reverse )
55
+ end
56
+
57
+ it "should delete all keys" do
58
+ ordered = []
59
+ @random_array.size.times do |t|
60
+ ordered << @heap.delete(@random_array[t])
61
+ end
62
+ @heap.should be_empty
63
+ ordered.should eql( @random_array )
64
+ end
65
+
66
+ it "should be in max->min order" do
67
+ ordered = []
68
+ ordered << @heap.max! until @heap.empty?
69
+
70
+ ordered.should eql(@random_array.sort.reverse)
71
+ end
72
+
73
+ it "should change certain keys" do
74
+ numbers = [1,2,3,4,5,6,7,8,9,10,100,101]
75
+ heap = Containers::MinHeap.new(numbers)
76
+ heap.change_key(101, 50)
77
+ heap.pop
78
+ heap.pop
79
+ heap.change_key(8, 0)
80
+ ordered = []
81
+ ordered << heap.min! until heap.empty?
82
+ ordered.should eql( [8,3,4,5,6,7,9,10,101,100] )
83
+ end
84
+
85
+ it "should not delete keys it doesn't have" do
86
+ @heap.delete(:nonexisting).should be_nil
87
+ @heap.size.should eql(@num_items)
88
+ end
89
+
90
+ it "should delete certain keys" do
91
+ numbers = [1,2,3,4,5,6,7,8,9,10,100,101]
92
+ heap = Containers::MinHeap.new(numbers)
93
+ heap.delete(5)
94
+ heap.pop
95
+ heap.pop
96
+ heap.delete(100)
97
+ ordered = []
98
+ ordered << heap.min! until heap.empty?
99
+ ordered.should eql( [3,4,6,7,8,9,10,101] )
100
+ end
101
+
102
+ it "should let you merge with another heap" do
103
+ numbers = [1,2,3,4,5,6,7,8]
104
+ otherheap = Containers::MaxHeap.new(numbers)
105
+ otherheap.size.should eql(8)
106
+ @heap.merge!(otherheap)
107
+
108
+ ordered = []
109
+ ordered << @heap.max! until @heap.empty?
110
+
111
+ ordered.should eql( (@random_array + numbers).sort.reverse)
112
+ end
113
+
114
+ describe "min-heap" do
115
+ it "should be in min->max order" do
116
+ @heap = Containers::MinHeap.new(@random_array)
117
+ ordered = []
118
+ ordered << @heap.min! until @heap.empty?
119
+
120
+ ordered.should eql(@random_array.sort)
121
+ end
122
+ end
123
+
124
+ end
125
+
126
+ end
@@ -0,0 +1,4 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ # TODO: KD Tree Spec
@@ -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
+ @q.size.should eql(0)
12
+ @q.should be_empty
13
+ end
14
+
15
+ it "should not return anything" do
16
+ @q.next.should be_nil
17
+ @q.pop.should be_nil
18
+ @q.delete(1).should be_nil
19
+ @q.has_priority?(1).should be_false
20
+ end
21
+
22
+ it "should give the correct size when adding items" do
23
+ 20.times do |i|
24
+ @q.size.should eql(i)
25
+ @q.push(i, i)
26
+ end
27
+ 10.times do |i|
28
+ @q.size.should eql(20-i)
29
+ @q.pop
30
+ end
31
+ 10.times do |i|
32
+ @q.size.should eql(i+10)
33
+ @q.push(i, i)
34
+ end
35
+ @q.delete(5)
36
+ @q.size.should 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
+ @q.next.should eql("Alaska")
49
+ @q.size.should eql(3)
50
+ @q.pop.should eql("Alaska")
51
+ @q.size.should eql(2)
52
+ end
53
+
54
+ it "should not be empty" do
55
+ @q.should_not be_empty
56
+ end
57
+
58
+ it "should has_priority? priorities it has" do
59
+ @q.has_priority?(50).should be_true
60
+ @q.has_priority?(10).should be_false
61
+ end
62
+
63
+ it "should return nil after popping everything" do
64
+ 3.times do
65
+ @q.pop
66
+ end
67
+ @q.pop.should be_nil
68
+ end
69
+
70
+ it "should delete things it has and not things it doesn't" do
71
+ @q.delete(50).should eql("Alaska")
72
+ @q.delete(10).should 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
+ @queue.pop.should be_nil
12
+ end
13
+
14
+ it "should return a size of 1 when sent #push" do
15
+ @queue.push(1)
16
+ @queue.size.should eql(1)
17
+ end
18
+
19
+ it "should return nil when sent #next" do
20
+ @queue.next.should be_nil
21
+ end
22
+
23
+ it "should return empty?" do
24
+ @queue.empty?.should 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
+ @queue.pop.should eql(10)
37
+ end
38
+
39
+ it "should return the size" do
40
+ @queue.size.should eql(2)
41
+ end
42
+
43
+ it "should not return empty?" do
44
+ @queue.empty?.should be_false
45
+ end
46
+
47
+ it "should iterate in FIFO order" do
48
+ arr = []
49
+ @queue.each { |obj| arr << obj }
50
+ arr.should 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
+ @queue.pop.should be_nil
58
+ @queue.next.should be_nil
59
+ end
60
+
61
+ end
@@ -0,0 +1,25 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ if defined? Containers::CRBTreeMap
5
+ describe "CRBTreeMap" 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
+ @tree = Containers::CRBTreeMap.new
14
+ 100.times { |x| @tree[anon_key_class.new(x)] = anon_val_class.new }
15
+ # Mark and sweep
16
+ ObjectSpace.garbage_collect
17
+ # Check if any instances were swept
18
+ count = 0
19
+ ObjectSpace.each_object(anon_key_class) { |x| count += 1 }
20
+ count.should eql(100)
21
+ ObjectSpace.each_object(anon_val_class) { |x| count += 1 }
22
+ count.should eql(200)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,123 @@
1
+ $: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
2
+ require 'algorithms'
3
+
4
+ describe "empty rbtree", :shared => true do
5
+ it "should let you push stuff in" do
6
+ 100.times { |x| @tree[x] = x }
7
+ @tree.size.should eql(100)
8
+ end
9
+
10
+ it "should be empty?" do
11
+ @tree.empty?.should be_true
12
+ end
13
+
14
+ it "should return 0 for height" do
15
+ @tree.height.should eql(0)
16
+ end
17
+
18
+ it "should return 0 for size" do
19
+ @tree.size.should eql(0)
20
+ end
21
+
22
+ it "should return nil for max and min" do
23
+ @tree.min.should be_nil
24
+ @tree.max.should be_nil
25
+ @tree.min_key.should be_nil
26
+ @tree.max_key.should be_nil
27
+ end
28
+
29
+ it "should not delete" do
30
+ @tree.delete(:non_existing).should be_nil
31
+ end
32
+ end
33
+
34
+ describe "non-empty rbtree", :shared => true 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
+ @tree.should_not be_empty
43
+ @tree.size.should eql(@random_array.uniq.size)
44
+ end
45
+
46
+ it "should return correct max and min" do
47
+ @tree.min_key.should eql(@random_array.min)
48
+ @tree.max_key.should eql(@random_array.max)
49
+ @tree.min[0].should eql(@random_array.min)
50
+ @tree.max[0].should eql(@random_array.max)
51
+ end
52
+
53
+ it "should not #has_key? keys it doesn't have" do
54
+ @tree.has_key?(100000).should be_false
55
+ end
56
+
57
+ it "should #has_key? keys it does have" do
58
+ @tree.has_key?(@random_array[0]).should be_true
59
+ end
60
+
61
+ it "should remove all keys" do
62
+ ordered = []
63
+ @random_array.uniq.each do |key|
64
+ @tree.has_key?(key).should eql(true)
65
+ ordered << @tree.delete(key)
66
+ @tree.has_key?(key).should eql(false)
67
+ end
68
+ ordered.should 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
+ ascending.should 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
+ descending.should 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
+ key.should 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