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 +7 -0
- data/CHANGELOG.markdown +8 -0
- data/Gemfile +9 -0
- data/README.markdown +40 -67
- data/Rakefile +20 -11
- data/algorithms.gemspec +12 -26
- 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/string.rb +1 -0
- data/lib/algorithms.rb +1 -0
- data/lib/containers/heap.rb +1 -9
- data/lib/containers/priority_queue.rb +0 -1
- data/lib/containers/rb_tree_map.rb +2 -2
- data/lib/containers/suffix_array.rb +3 -3
- data/lib/containers/trie.rb +1 -1
- data/spec/deque_gc_mark_spec.rb +1 -1
- data/spec/deque_spec.rb +18 -18
- data/spec/heap_spec.rb +211 -25
- data/spec/kd_tree_spec.rb +2 -2
- data/spec/map_gc_mark_spec.rb +23 -21
- 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 +10 -8
- data/spec/suffix_array_spec.rb +17 -17
- data/spec/trie_spec.rb +16 -16
- metadata +21 -72
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
|
@@ -1,35 +1,221 @@
|
|
|
1
1
|
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
|
2
2
|
require 'algorithms'
|
|
3
3
|
|
|
4
|
+
include Comparable
|
|
5
|
+
|
|
6
|
+
class Book
|
|
7
|
+
attr_reader :title, :year_published
|
|
8
|
+
|
|
9
|
+
def initialize(title, year_published)
|
|
10
|
+
@title = title
|
|
11
|
+
@year_published = year_published
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def <=>(other)
|
|
15
|
+
return nil unless other.is_a?(Book)
|
|
16
|
+
|
|
17
|
+
# 1. Compare by year first
|
|
18
|
+
year_comparison = self.year_published <=> other.year_published
|
|
19
|
+
|
|
20
|
+
# 2. If years are different, return that comparison result
|
|
21
|
+
return year_comparison unless year_comparison == 0
|
|
22
|
+
|
|
23
|
+
# 3. If years are the same (tie), compare by title alphabetically
|
|
24
|
+
# (Ensure title comparison returns -1, 0, or 1)
|
|
25
|
+
self.title <=> other.title
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
"\"#{title}\" (#{year_published})" # Simplified for test output
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Add an equality method for clearer test failures if needed,
|
|
34
|
+
# though <=> returning 0 handles equality for sorting/heap purposes.
|
|
35
|
+
def ==(other)
|
|
36
|
+
other.is_a?(Book) &&
|
|
37
|
+
self.title == other.title &&
|
|
38
|
+
self.year_published == other.year_published
|
|
39
|
+
end
|
|
40
|
+
alias eql? ==
|
|
41
|
+
|
|
42
|
+
def hash
|
|
43
|
+
[title, year_published].hash
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe ::Containers::Heap do
|
|
49
|
+
|
|
50
|
+
# --- Test Data Setup ---
|
|
51
|
+
let!(:book_1932) { Book.new("Brave New World", 1932) }
|
|
52
|
+
let!(:book_1949) { Book.new("1984", 1949) }
|
|
53
|
+
let!(:book_1951a) { Book.new("Foundation", 1951) }
|
|
54
|
+
# Add another book from the same year to test handling of equal priority items
|
|
55
|
+
let!(:book_1951b) { Book.new("The Illustrated Man", 1951) }
|
|
56
|
+
let!(:book_1965) { Book.new("Dune", 1965) }
|
|
57
|
+
let!(:book_1989) { Book.new("Hyperion", 1989) }
|
|
58
|
+
|
|
59
|
+
# Use shuffle to ensure tests don't depend on insertion order
|
|
60
|
+
let(:books) { [book_1965, book_1951a, book_1989, book_1949, book_1932, book_1951b].shuffle }
|
|
61
|
+
|
|
62
|
+
let(:expected_min_order) { books.sort }
|
|
63
|
+
|
|
64
|
+
let(:expected_max_order) { books.sort.reverse }
|
|
65
|
+
|
|
66
|
+
context "Min-Heap (using default <=> via Comparable)" do
|
|
67
|
+
# Initialize heap with books; it should use Book#<=> by default
|
|
68
|
+
let(:min_heap) { ::Containers::Heap.new(books) }
|
|
69
|
+
|
|
70
|
+
it "initializes with the correct size" do
|
|
71
|
+
expect(min_heap.size).to eq(books.size)
|
|
72
|
+
expect(min_heap.empty?).to be false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "gets the next minimum element (earliest year) without removing it" do
|
|
76
|
+
# next should return the element with the smallest year_published
|
|
77
|
+
expect(min_heap.next).to eq(book_1932)
|
|
78
|
+
# next should not change the size
|
|
79
|
+
expect(min_heap.size).to eq(books.size)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "pops elements in ascending order of year_published" do
|
|
83
|
+
popped_books = []
|
|
84
|
+
while (book = min_heap.pop)
|
|
85
|
+
popped_books << book
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Verify the popped order matches the expected sorted order
|
|
89
|
+
expect(popped_books).to eq(expected_min_order)
|
|
90
|
+
|
|
91
|
+
# Verify the heap is now empty
|
|
92
|
+
expect(min_heap.size).to eq(0)
|
|
93
|
+
expect(min_heap.empty?).to be true
|
|
94
|
+
expect(min_heap.pop).to be_nil # Popping an empty heap
|
|
95
|
+
expect(min_heap.next).to be_nil # Getting next from an empty heap
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "correctly updates size after popping" do
|
|
99
|
+
expect(min_heap.size).to eq(books.size)
|
|
100
|
+
min_heap.pop
|
|
101
|
+
expect(min_heap.size).to eq(books.size - 1)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
context "Max-Heap (using a custom comparison block)" do
|
|
107
|
+
# Initialize heap with books and a block for max-heap behavior
|
|
108
|
+
# The block returns true if x should have higher priority (be "larger") than y
|
|
109
|
+
let(:max_heap) { ::Containers::Heap.new(books) { |x, y| x > y } } # Use > from Comparable
|
|
110
|
+
|
|
111
|
+
it "initializes with the correct size" do
|
|
112
|
+
expect(max_heap.size).to eq(books.size)
|
|
113
|
+
expect(max_heap.empty?).to be false
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "gets the next maximum element (latest year) without removing it" do
|
|
117
|
+
# next should return the element with the largest year_published
|
|
118
|
+
expect(max_heap.next).to eq(book_1989)
|
|
119
|
+
# next should not change the size
|
|
120
|
+
expect(max_heap.size).to eq(books.size)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "pops elements in descending order of year_published" do
|
|
124
|
+
popped_books = []
|
|
125
|
+
while (book = max_heap.pop)
|
|
126
|
+
popped_books << book
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Verify the popped order matches the expected reversed sorted order
|
|
130
|
+
expect(popped_books).to eq(expected_max_order)
|
|
131
|
+
|
|
132
|
+
# Verify the heap is now empty
|
|
133
|
+
expect(max_heap.size).to eq(0)
|
|
134
|
+
expect(max_heap.empty?).to be true
|
|
135
|
+
expect(max_heap.pop).to be_nil # Popping an empty heap
|
|
136
|
+
expect(max_heap.next).to be_nil # Getting next from an empty heap
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "correctly updates size after popping" do
|
|
140
|
+
expect(max_heap.size).to eq(books.size)
|
|
141
|
+
max_heap.pop
|
|
142
|
+
expect(max_heap.size).to eq(books.size - 1)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
context "Edge cases" do
|
|
147
|
+
it "handles an empty initialization" do
|
|
148
|
+
heap = ::Containers::Heap.new([])
|
|
149
|
+
expect(heap.size).to eq(0)
|
|
150
|
+
expect(heap.empty?).to be true
|
|
151
|
+
expect(heap.pop).to be_nil
|
|
152
|
+
expect(heap.next).to be_nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "handles initialization with one element" do
|
|
156
|
+
heap = ::Containers::Heap.new([book_1965])
|
|
157
|
+
expect(heap.size).to eq(1)
|
|
158
|
+
expect(heap.next).to eq(book_1965)
|
|
159
|
+
expect(heap.pop).to eq(book_1965)
|
|
160
|
+
expect(heap.empty?).to be true
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
end
|
|
165
|
+
|
|
4
166
|
describe Containers::Heap do
|
|
5
167
|
before(:each) do
|
|
6
168
|
@heap = Containers::MaxHeap.new
|
|
7
169
|
end
|
|
170
|
+
|
|
171
|
+
it "should run without error when given Objects and a non-ordering comparator" do
|
|
172
|
+
# Create and store the initial distinct objects
|
|
173
|
+
initial_objects = 10.times.map { Object.new }
|
|
174
|
+
initial_object_ids = initial_objects.map(&:object_id) # Store IDs for comparison
|
|
175
|
+
|
|
176
|
+
min_heap = ::Containers::Heap.new(initial_objects) { |x, y| (x <=> y) == -1 }
|
|
177
|
+
|
|
178
|
+
expect(min_heap.size).to eq(10)
|
|
179
|
+
|
|
180
|
+
popped_elements = []
|
|
181
|
+
expect {
|
|
182
|
+
while val = min_heap.pop do
|
|
183
|
+
popped_elements << val
|
|
184
|
+
end
|
|
185
|
+
}.not_to raise_error
|
|
186
|
+
|
|
187
|
+
expect(min_heap.empty?).to be true
|
|
188
|
+
expect(popped_elements.size).to eq(10)
|
|
189
|
+
|
|
190
|
+
# Assert that exactly the same objects were returned, regardless of order.
|
|
191
|
+
# Comparing by object_id is the most reliable way for distinct Objects.
|
|
192
|
+
expect(popped_elements.map(&:object_id)).to contain_exactly(*initial_object_ids)
|
|
193
|
+
end
|
|
8
194
|
|
|
9
195
|
it "should not let you merge with non-heaps" do
|
|
10
|
-
|
|
11
|
-
|
|
196
|
+
expect { @heap.merge!(nil) }.to raise_error(ArgumentError)
|
|
197
|
+
expect { @heap.merge!([]) }.to raise_error(ArgumentError)
|
|
12
198
|
end
|
|
13
199
|
|
|
14
200
|
describe "(empty)" do
|
|
15
201
|
|
|
16
202
|
it "should return nil when getting the maximum" do
|
|
17
|
-
@heap.max
|
|
203
|
+
expect(@heap.max!).to be_nil
|
|
18
204
|
end
|
|
19
205
|
|
|
20
206
|
it "should let you insert and remove one item" do
|
|
21
|
-
@heap.size.
|
|
207
|
+
expect(@heap.size).to eql(0)
|
|
22
208
|
|
|
23
209
|
@heap.push(1)
|
|
24
|
-
@heap.size.
|
|
210
|
+
expect(@heap.size).to eql(1)
|
|
25
211
|
|
|
26
|
-
@heap.max
|
|
27
|
-
@heap.size.
|
|
212
|
+
expect(@heap.max!).to eql(1)
|
|
213
|
+
expect(@heap.size).to eql(0)
|
|
28
214
|
end
|
|
29
215
|
|
|
30
216
|
it "should let you initialize with an array" do
|
|
31
217
|
@heap = Containers::MaxHeap.new([1,2,3])
|
|
32
|
-
@heap.size.
|
|
218
|
+
expect(@heap.size).to eql(3)
|
|
33
219
|
end
|
|
34
220
|
|
|
35
221
|
end
|
|
@@ -38,25 +224,25 @@ describe Containers::Heap do
|
|
|
38
224
|
before(:each) do
|
|
39
225
|
@random_array = []
|
|
40
226
|
@num_items = 100
|
|
41
|
-
@num_items.times {
|
|
227
|
+
@num_items.times { @random_array << rand(@num_items) }
|
|
42
228
|
@heap = Containers::MaxHeap.new(@random_array)
|
|
43
229
|
end
|
|
44
230
|
|
|
45
231
|
it "should display the correct size" do
|
|
46
|
-
@heap.size.
|
|
232
|
+
expect(@heap.size).to eql(@num_items)
|
|
47
233
|
end
|
|
48
234
|
|
|
49
235
|
it "should have a next value" do
|
|
50
|
-
@heap.next.
|
|
51
|
-
@heap.next_key.
|
|
236
|
+
expect(@heap.next).to be_truthy
|
|
237
|
+
expect(@heap.next_key).to be_truthy
|
|
52
238
|
end
|
|
53
239
|
|
|
54
240
|
it "should delete random keys" do
|
|
55
|
-
@heap.delete(@random_array[0]).
|
|
56
|
-
@heap.delete(@random_array[1]).
|
|
241
|
+
expect(@heap.delete(@random_array[0])).to eql(@random_array[0])
|
|
242
|
+
expect(@heap.delete(@random_array[1])).to eql(@random_array[1])
|
|
57
243
|
ordered = []
|
|
58
244
|
ordered << @heap.max! until @heap.empty?
|
|
59
|
-
ordered.
|
|
245
|
+
expect(ordered).to eql( @random_array[2..-1].sort.reverse )
|
|
60
246
|
end
|
|
61
247
|
|
|
62
248
|
it "should delete all keys" do
|
|
@@ -64,15 +250,15 @@ describe Containers::Heap do
|
|
|
64
250
|
@random_array.size.times do |t|
|
|
65
251
|
ordered << @heap.delete(@random_array[t])
|
|
66
252
|
end
|
|
67
|
-
@heap.
|
|
68
|
-
ordered.
|
|
253
|
+
expect(@heap).to be_empty
|
|
254
|
+
expect(ordered).to eql( @random_array )
|
|
69
255
|
end
|
|
70
256
|
|
|
71
257
|
it "should be in max->min order" do
|
|
72
258
|
ordered = []
|
|
73
259
|
ordered << @heap.max! until @heap.empty?
|
|
74
260
|
|
|
75
|
-
ordered.
|
|
261
|
+
expect(ordered).to eql(@random_array.sort.reverse)
|
|
76
262
|
end
|
|
77
263
|
|
|
78
264
|
it "should change certain keys" do
|
|
@@ -84,12 +270,12 @@ describe Containers::Heap do
|
|
|
84
270
|
heap.change_key(8, 0)
|
|
85
271
|
ordered = []
|
|
86
272
|
ordered << heap.min! until heap.empty?
|
|
87
|
-
ordered.
|
|
273
|
+
expect(ordered).to eql( [8,3,4,5,6,7,9,10,101,100] )
|
|
88
274
|
end
|
|
89
275
|
|
|
90
276
|
it "should not delete keys it doesn't have" do
|
|
91
|
-
@heap.delete(:nonexisting).
|
|
92
|
-
@heap.size.
|
|
277
|
+
expect(@heap.delete(:nonexisting)).to be_nil
|
|
278
|
+
expect(@heap.size).to eql(@num_items)
|
|
93
279
|
end
|
|
94
280
|
|
|
95
281
|
it "should delete certain keys" do
|
|
@@ -101,19 +287,19 @@ describe Containers::Heap do
|
|
|
101
287
|
heap.delete(100)
|
|
102
288
|
ordered = []
|
|
103
289
|
ordered << heap.min! until heap.empty?
|
|
104
|
-
ordered.
|
|
290
|
+
expect(ordered).to eql( [3,4,6,7,8,9,10,101] )
|
|
105
291
|
end
|
|
106
292
|
|
|
107
293
|
it "should let you merge with another heap" do
|
|
108
294
|
numbers = [1,2,3,4,5,6,7,8]
|
|
109
295
|
otherheap = Containers::MaxHeap.new(numbers)
|
|
110
|
-
otherheap.size.
|
|
296
|
+
expect(otherheap.size).to eql(8)
|
|
111
297
|
@heap.merge!(otherheap)
|
|
112
298
|
|
|
113
299
|
ordered = []
|
|
114
300
|
ordered << @heap.max! until @heap.empty?
|
|
115
301
|
|
|
116
|
-
ordered.
|
|
302
|
+
expect(ordered).to eql( (@random_array + numbers).sort.reverse)
|
|
117
303
|
end
|
|
118
304
|
|
|
119
305
|
describe "min-heap" do
|
|
@@ -122,7 +308,7 @@ describe Containers::Heap do
|
|
|
122
308
|
ordered = []
|
|
123
309
|
ordered << @heap.min! until @heap.empty?
|
|
124
310
|
|
|
125
|
-
ordered.
|
|
311
|
+
expect(ordered).to eql(@random_array.sort)
|
|
126
312
|
end
|
|
127
313
|
end
|
|
128
314
|
|
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
|
data/spec/map_gc_mark_spec.rb
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
$: << File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib')
|
|
2
2
|
require 'algorithms'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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)
|
|
10
27
|
end
|
|
11
|
-
anon_val_class = Class.new
|
|
12
|
-
@rbtree = Containers::CRBTreeMap.new
|
|
13
|
-
@splaytree = Containers::CSplayTreeMap.new
|
|
14
|
-
100.times { |x|
|
|
15
|
-
@rbtree[anon_key_class.new(x)] = anon_val_class.new
|
|
16
|
-
@splaytree[anon_key_class.new(x)] = anon_val_class.new
|
|
17
|
-
}
|
|
18
|
-
# Mark and sweep
|
|
19
|
-
ObjectSpace.garbage_collect
|
|
20
|
-
# Check if any instances were swept
|
|
21
|
-
count = 0
|
|
22
|
-
ObjectSpace.each_object(anon_key_class) { |x| count += 1 }
|
|
23
|
-
count.should eql(200)
|
|
24
|
-
ObjectSpace.each_object(anon_val_class) { |x| count += 1 }
|
|
25
|
-
count.should eql(400)
|
|
26
28
|
end
|
|
27
29
|
end
|
data/spec/priority_queue_spec.rb
CHANGED
|
@@ -8,32 +8,32 @@ describe Containers::PriorityQueue do
|
|
|
8
8
|
|
|
9
9
|
describe "(empty priority queue)" do
|
|
10
10
|
it "should return 0 for size and be empty" do
|
|
11
|
-
@q.size.
|
|
12
|
-
@q.
|
|
11
|
+
expect(@q.size).to eql(0)
|
|
12
|
+
expect(@q).to be_empty
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
it "should not return anything" do
|
|
16
|
-
@q.next.
|
|
17
|
-
@q.pop.
|
|
18
|
-
@q.delete(1).
|
|
19
|
-
@q.has_priority?(1).
|
|
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
20
|
end
|
|
21
21
|
|
|
22
22
|
it "should give the correct size when adding items" do
|
|
23
23
|
20.times do |i|
|
|
24
|
-
@q.size.
|
|
24
|
+
expect(@q.size).to eql(i)
|
|
25
25
|
@q.push(i, i)
|
|
26
26
|
end
|
|
27
27
|
10.times do |i|
|
|
28
|
-
@q.size.
|
|
28
|
+
expect(@q.size).to eql(20-i)
|
|
29
29
|
@q.pop
|
|
30
30
|
end
|
|
31
31
|
10.times do |i|
|
|
32
|
-
@q.size.
|
|
32
|
+
expect(@q.size).to eql(i+10)
|
|
33
33
|
@q.push(i, i)
|
|
34
34
|
end
|
|
35
35
|
@q.delete(5)
|
|
36
|
-
@q.size.
|
|
36
|
+
expect(@q.size).to eql(19)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -45,31 +45,31 @@ describe Containers::PriorityQueue do
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it "should next/pop the highest priority" do
|
|
48
|
-
@q.next.
|
|
49
|
-
@q.size.
|
|
50
|
-
@q.pop.
|
|
51
|
-
@q.size.
|
|
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
52
|
end
|
|
53
53
|
|
|
54
54
|
it "should not be empty" do
|
|
55
|
-
@q.
|
|
55
|
+
expect(@q).not_to be_empty
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
it "should has_priority? priorities it has" do
|
|
59
|
-
@q.has_priority?(50).
|
|
60
|
-
@q.has_priority?(10).
|
|
59
|
+
expect(@q.has_priority?(50)).to be true
|
|
60
|
+
expect(@q.has_priority?(10)).to be false
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
it "should return nil after popping everything" do
|
|
64
64
|
3.times do
|
|
65
65
|
@q.pop
|
|
66
66
|
end
|
|
67
|
-
@q.pop.
|
|
67
|
+
expect(@q.pop).to be_nil
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
it "should delete things it has and not things it doesn't" do
|
|
71
|
-
@q.delete(50).
|
|
72
|
-
@q.delete(10).
|
|
71
|
+
expect(@q.delete(50)).to eql("Alaska")
|
|
72
|
+
expect(@q.delete(10)).to eql(nil)
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
end
|
data/spec/queue_spec.rb
CHANGED
|
@@ -8,20 +8,20 @@ describe "empty queue" do
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
it "should return nil when sent #pop" do
|
|
11
|
-
@queue.pop.
|
|
11
|
+
expect(@queue.pop).to be_nil
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it "should return a size of 1 when sent #push" do
|
|
15
15
|
@queue.push(1)
|
|
16
|
-
@queue.size.
|
|
16
|
+
expect(@queue.size).to eql(1)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
it "should return nil when sent #next" do
|
|
20
|
-
@queue.next.
|
|
20
|
+
expect(@queue.next).to be_nil
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
it "should return empty?" do
|
|
24
|
-
@queue.empty
|
|
24
|
+
expect(@queue.empty?).to be true
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
@@ -33,29 +33,29 @@ describe "non-empty queue" do
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "should return first pushed object" do
|
|
36
|
-
@queue.pop.
|
|
36
|
+
expect(@queue.pop).to eql(10)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
it "should return the size" do
|
|
40
|
-
@queue.size.
|
|
40
|
+
expect(@queue.size).to eql(2)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
it "should not return empty?" do
|
|
44
|
-
@queue.empty
|
|
44
|
+
expect(@queue.empty?).to be false
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it "should iterate in FIFO order" do
|
|
48
48
|
arr = []
|
|
49
49
|
@queue.each { |obj| arr << obj }
|
|
50
|
-
arr.
|
|
50
|
+
expect(arr).to eql([10, "10"])
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
it "should return nil after all gets" do
|
|
54
54
|
2.times do
|
|
55
55
|
@queue.pop
|
|
56
56
|
end
|
|
57
|
-
@queue.pop.
|
|
58
|
-
@queue.next.
|
|
57
|
+
expect(@queue.pop).to be_nil
|
|
58
|
+
expect(@queue.next).to be_nil
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
end
|