algorithms 0.0.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.
- data/History.txt +23 -0
- data/Manifest +23 -0
- data/README.txt +58 -0
- data/Rakefile +17 -0
- data/algorithms.gemspec +105 -0
- data/benchmark.rb +49 -0
- data/ext/containers/priority_queue/extconf.rb +4 -0
- data/ext/containers/priority_queue/priority_queue.c +948 -0
- data/ext/containers/tree_map/Rakefile +4 -0
- data/ext/containers/tree_map/extconf.rb +4 -0
- data/ext/containers/tree_map/rbtree.c +395 -0
- data/lib/algorithms.rb +7 -0
- data/lib/containers/hash.rb +0 -0
- data/lib/containers/heap.rb +146 -0
- data/lib/containers/priority_queue.rb +514 -0
- data/lib/containers/queue.rb +29 -0
- data/lib/containers/stack.rb +29 -0
- data/lib/containers/tree_map.rb +265 -0
- data/spec/heap_spec.rb +74 -0
- data/spec/priority_queue_spec.rb +31 -0
- data/spec/priority_queue_test.rb +371 -0
- data/spec/queue_spec.rb +53 -0
- data/spec/stack_spec.rb +53 -0
- data/spec/tree_map_spec.rb +99 -0
- metadata +104 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module Containers
|
2
|
+
# Use a Ruby array for storage
|
3
|
+
class Queue
|
4
|
+
def initialize(ary=[])
|
5
|
+
@container = ary
|
6
|
+
end
|
7
|
+
|
8
|
+
def put(object)
|
9
|
+
@container.push(object)
|
10
|
+
end
|
11
|
+
|
12
|
+
def peek
|
13
|
+
@container[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
def get
|
17
|
+
@container.shift
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
@container.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def empty?
|
25
|
+
@container.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Containers
|
2
|
+
# Use a Ruby array for storage
|
3
|
+
class Stack
|
4
|
+
def initialize(ary=[])
|
5
|
+
@container = ary
|
6
|
+
end
|
7
|
+
|
8
|
+
def push(object)
|
9
|
+
@container.push(object)
|
10
|
+
end
|
11
|
+
|
12
|
+
def peek
|
13
|
+
@container.last
|
14
|
+
end
|
15
|
+
|
16
|
+
def pop
|
17
|
+
@container.pop
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
@container.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def empty?
|
25
|
+
@container.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
module Containers
|
2
|
+
# A TreeMap implemented with a self-balancing red-black tree
|
3
|
+
# Adapted from Robert Sedgewick's Left Leaning Red-Black Tree Implementation
|
4
|
+
# http://www.cs.princeton.edu/~rs/talks/LLRB/Java/RedBlackBST.java
|
5
|
+
class RubyTreeMap
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
class Node
|
9
|
+
attr_accessor :color, :key, :value, :left, :right, :num_nodes, :height
|
10
|
+
def initialize(key, value)
|
11
|
+
@key = key
|
12
|
+
@value = value
|
13
|
+
@color = :red
|
14
|
+
@left = nil
|
15
|
+
@right = nil
|
16
|
+
@num_nodes = 1
|
17
|
+
@height = 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :height_black
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@root = nil
|
25
|
+
@height_black = 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def put(key, value)
|
29
|
+
@root = insert(@root, key, value)
|
30
|
+
@height_black += 1 if isred(@root)
|
31
|
+
@root.color = :black
|
32
|
+
end
|
33
|
+
alias :[]= :put
|
34
|
+
|
35
|
+
def size
|
36
|
+
sizeR(@root)
|
37
|
+
end
|
38
|
+
|
39
|
+
def height
|
40
|
+
heightR(@root)
|
41
|
+
end
|
42
|
+
|
43
|
+
def contains?(key)
|
44
|
+
!get(key).nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def get(key)
|
48
|
+
getR(@root, key)
|
49
|
+
end
|
50
|
+
alias :[] :get
|
51
|
+
|
52
|
+
def min_key
|
53
|
+
@root.nil? ? nil : minR(@root)
|
54
|
+
end
|
55
|
+
|
56
|
+
def max_key
|
57
|
+
@root.nil? ? nil : maxR(@root)
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(key)
|
61
|
+
result = nil
|
62
|
+
if @root
|
63
|
+
@root, result = deleteR(@root, key)
|
64
|
+
@root.color = :black
|
65
|
+
end
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def each(&block)
|
70
|
+
@root.nil? ? nil : eachR(@root, block)
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_s
|
74
|
+
return "" if @root.nil?
|
75
|
+
"#{@height_black} #{to_sR(@root)}"
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def eachR(node, block)
|
81
|
+
return if node.nil?
|
82
|
+
|
83
|
+
eachR(node.left, block)
|
84
|
+
block.call(node.key, node.value)
|
85
|
+
eachR(node.right, block)
|
86
|
+
end
|
87
|
+
|
88
|
+
def deleteR(node, key)
|
89
|
+
if (key <=> node.key) == -1
|
90
|
+
node = move_red_left(node) if (!isred(node.left) && !isred(node.left.left))
|
91
|
+
node.left, result = deleteR(node.left, key)
|
92
|
+
else
|
93
|
+
node = rotate_right(node) if isred(node.left)
|
94
|
+
if ( ( (key <=> node.key) == 0) && node.right.nil? )
|
95
|
+
return nil, node.value
|
96
|
+
end
|
97
|
+
if (!isred(node.right) && !isred(node.right.left))
|
98
|
+
node = move_red_right(node);
|
99
|
+
end
|
100
|
+
if (key <=> node.key) == 0
|
101
|
+
result = node.value
|
102
|
+
node.value = getR(node.right, minR(node.right))
|
103
|
+
node.key = minR(node.right)
|
104
|
+
node.right = delete_minR(node.right)
|
105
|
+
else
|
106
|
+
node.right, result = deleteR(node.right, key)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
return fixup(node), result
|
110
|
+
end
|
111
|
+
|
112
|
+
def delete_minR(node)
|
113
|
+
return nil if node.left.nil?
|
114
|
+
if ( !isred(node.left) && !isred(node.left.left) )
|
115
|
+
node = move_red_left(node)
|
116
|
+
end
|
117
|
+
node.left = delete_minR(node.left)
|
118
|
+
|
119
|
+
fixup(node)
|
120
|
+
end
|
121
|
+
|
122
|
+
def delete_maxR(node)
|
123
|
+
if (isred(node.left))
|
124
|
+
node = rotate_right(node)
|
125
|
+
end
|
126
|
+
return nil if node.right.nil?
|
127
|
+
if ( !isred(node.right) && !isred(node.right.left) )
|
128
|
+
node = move_red_right(node)
|
129
|
+
end
|
130
|
+
node.right = delete_maxR(node.right)
|
131
|
+
|
132
|
+
fixup(node)
|
133
|
+
end
|
134
|
+
|
135
|
+
def getR(node, key)
|
136
|
+
return nil if node.nil?
|
137
|
+
case key <=> node.key
|
138
|
+
when 0 then return node.value;
|
139
|
+
when -1 then return getR(node.left, key)
|
140
|
+
when 1 then return getR(node.right, key)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_sR(x)
|
145
|
+
s = "("
|
146
|
+
x.left.nil? ? s << '(' : s << to_sR(x.left)
|
147
|
+
s << "*" if isred(x)
|
148
|
+
x.right.nil? ? s << ')' : s << to_sR(x.right)
|
149
|
+
s + ')'
|
150
|
+
end
|
151
|
+
|
152
|
+
def sizeR(node)
|
153
|
+
return 0 if node.nil?
|
154
|
+
|
155
|
+
node.num_nodes
|
156
|
+
end
|
157
|
+
|
158
|
+
def heightR(node)
|
159
|
+
return 0 if node.nil?
|
160
|
+
|
161
|
+
node.height
|
162
|
+
end
|
163
|
+
|
164
|
+
def minR(node)
|
165
|
+
return node.key if node.left.nil?
|
166
|
+
|
167
|
+
minR(node.left)
|
168
|
+
end
|
169
|
+
|
170
|
+
def maxR(node)
|
171
|
+
return node.key if node.right.nil?
|
172
|
+
|
173
|
+
maxR(node.right)
|
174
|
+
end
|
175
|
+
|
176
|
+
def insert(node, key, value)
|
177
|
+
if(node.nil?)
|
178
|
+
return Node.new(key, value)
|
179
|
+
end
|
180
|
+
|
181
|
+
colorflip(node) if (isred(node.left) && isred(node.right))
|
182
|
+
|
183
|
+
case key <=> node.key
|
184
|
+
when 0 then node.value = value
|
185
|
+
when -1 then node.left = insert(node.left, key, value)
|
186
|
+
when 1 then node.right = insert(node.right, key, value)
|
187
|
+
end
|
188
|
+
|
189
|
+
node = rotate_left(node) if isred(node.right)
|
190
|
+
node = rotate_right(node) if (isred(node.left) && isred(node.left.left))
|
191
|
+
|
192
|
+
set_num_nodes(node)
|
193
|
+
end
|
194
|
+
|
195
|
+
def isred(h)
|
196
|
+
return false if h.nil?
|
197
|
+
|
198
|
+
h.color == :red
|
199
|
+
end
|
200
|
+
|
201
|
+
def rotate_left(h)
|
202
|
+
x = h.right
|
203
|
+
h.right = x.left
|
204
|
+
x.left = set_num_nodes(h)
|
205
|
+
x.color = x.left.color
|
206
|
+
x.left.color = :red
|
207
|
+
|
208
|
+
set_num_nodes(x)
|
209
|
+
end
|
210
|
+
|
211
|
+
def rotate_right(h)
|
212
|
+
x = h.left
|
213
|
+
h.left = x.right
|
214
|
+
x.right = set_num_nodes(h)
|
215
|
+
x.color = x.right.color
|
216
|
+
x.right.color = :red
|
217
|
+
|
218
|
+
set_num_nodes(x);
|
219
|
+
end
|
220
|
+
|
221
|
+
def colorflip(h)
|
222
|
+
h.color = h.color == :red ? :black : :red
|
223
|
+
h.left.color = h.left.color == :red ? :black : :red
|
224
|
+
h.right.color = h.right.color == :red ? :black : :red
|
225
|
+
end
|
226
|
+
|
227
|
+
def move_red_left(h)
|
228
|
+
colorflip(h)
|
229
|
+
if isred(h.right.left)
|
230
|
+
h.right = rotate_right(h.right)
|
231
|
+
h = rotate_left(h)
|
232
|
+
colorflip(h)
|
233
|
+
end
|
234
|
+
h
|
235
|
+
end
|
236
|
+
|
237
|
+
def move_red_right(h)
|
238
|
+
colorflip(h)
|
239
|
+
if isred(h.left.left)
|
240
|
+
h = rotate_right(h)
|
241
|
+
colorflip(h)
|
242
|
+
end
|
243
|
+
h
|
244
|
+
end
|
245
|
+
|
246
|
+
def fixup(h)
|
247
|
+
h = rotate_left(h) if isred(h.right)
|
248
|
+
h = rotate_right(h) if (isred(h.left) && isred(h.left.left))
|
249
|
+
colorflip(h) if (isred(h.left) && isred(h.right))
|
250
|
+
|
251
|
+
set_num_nodes(h)
|
252
|
+
end
|
253
|
+
|
254
|
+
def set_num_nodes(h)
|
255
|
+
h.num_nodes = sizeR(h.left) + sizeR(h.right) + 1
|
256
|
+
if heightR(h.left) > heightR(h.right)
|
257
|
+
h.height = heightR(h.left) + 1
|
258
|
+
else
|
259
|
+
h.height = heightR(h.right) + 1
|
260
|
+
end
|
261
|
+
h
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
data/spec/heap_spec.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'lib/algorithms'
|
2
|
+
|
3
|
+
describe Containers::Heap do
|
4
|
+
before(:each) do
|
5
|
+
@heap = Containers::MaxHeap.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "(empty)" do
|
9
|
+
|
10
|
+
it "should return nil when getting the maximum" do
|
11
|
+
@heap.get_max!.should eql(nil)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should let you insert and remove one item" do
|
15
|
+
@heap.size.should eql(0)
|
16
|
+
|
17
|
+
@heap.insert(1)
|
18
|
+
@heap.size.should eql(1)
|
19
|
+
|
20
|
+
@heap.get_max!.should eql(1)
|
21
|
+
@heap.size.should eql(0)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should let you initialize with an array" do
|
25
|
+
@heap = Containers::MaxHeap.new([1,2,3])
|
26
|
+
@heap.size.should eql(3)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "(non-empty)" do
|
32
|
+
before(:each) do
|
33
|
+
@random_array = []
|
34
|
+
@num_items = 100
|
35
|
+
@num_items.times { |x| @random_array << rand(@num_items) }
|
36
|
+
@heap = Containers::MaxHeap.new(@random_array)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should display the correct size" do
|
40
|
+
@heap.size.should eql(@num_items)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should be in max->min order" do
|
44
|
+
ordered = []
|
45
|
+
ordered << @heap.get_max! until @heap.size == 0
|
46
|
+
|
47
|
+
ordered.should eql(@random_array.sort.reverse)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should let you merge with another heap" do
|
51
|
+
numbers = [1,3,4,5]
|
52
|
+
otherheap = Containers::MaxHeap.new(numbers)
|
53
|
+
otherheap.size.should eql(4)
|
54
|
+
@heap.merge!(otherheap)
|
55
|
+
|
56
|
+
ordered = []
|
57
|
+
ordered << @heap.get_max! until @heap.size == 0
|
58
|
+
|
59
|
+
ordered.should eql( (@random_array + numbers).sort.reverse)
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "min-heap" do
|
63
|
+
it "should be in min->max order" do
|
64
|
+
@heap = Containers::MinHeap.new(@random_array)
|
65
|
+
ordered = []
|
66
|
+
ordered << @heap.get_min! until @heap.size == 0
|
67
|
+
|
68
|
+
ordered.should eql(@random_array.sort)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'lib/algorithms'
|
2
|
+
|
3
|
+
describe Containers::RubyPriorityQueue do
|
4
|
+
before(:each) do
|
5
|
+
@q = Containers::RubyPriorityQueue.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "(empty)" do
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "(non-empty)" do
|
13
|
+
it "should give the correct length/size" do
|
14
|
+
20.times do | i |
|
15
|
+
@q.length.should eql(i)
|
16
|
+
@q[i] = i
|
17
|
+
end
|
18
|
+
10.times do | i |
|
19
|
+
@q.length.should eql(20-i)
|
20
|
+
@q.delete_min
|
21
|
+
end
|
22
|
+
10.times do | i |
|
23
|
+
@q.length.should eql(i+10)
|
24
|
+
@q[i] = i
|
25
|
+
end
|
26
|
+
@q.delete(5)
|
27
|
+
@q.length.should eql(19)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,371 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Priority Queue tests
|
4
|
+
|
5
|
+
$:.unshift '../ext/priority_queue/CPriorityQueue'
|
6
|
+
$:.unshift '../lib/'
|
7
|
+
|
8
|
+
require 'test/unit'
|
9
|
+
|
10
|
+
require 'priority_queue/ruby_priority_queue'
|
11
|
+
require 'priority_queue/poor_priority_queue'
|
12
|
+
begin
|
13
|
+
require 'priority_queue/CPriorityQueue'
|
14
|
+
rescue LoadError
|
15
|
+
require 'CPriorityQueue'
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
module PriorityQueueTest
|
20
|
+
# Check that the order is maintained
|
21
|
+
def teardown
|
22
|
+
last = @q.min_priority
|
23
|
+
while priority = @q.delete_min_return_priority
|
24
|
+
assert_operator(last, :<=, priority)
|
25
|
+
last = priority
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_length
|
30
|
+
20.times do | i |
|
31
|
+
assert_equal(i, @q.length)
|
32
|
+
@q[i] = i
|
33
|
+
end
|
34
|
+
10.times do | i |
|
35
|
+
assert_equal(20-i, @q.length)
|
36
|
+
@q.delete_min
|
37
|
+
end
|
38
|
+
10.times do | i |
|
39
|
+
assert_equal(10+i, @q.length)
|
40
|
+
@q[i] = i
|
41
|
+
end
|
42
|
+
@q.delete(5)
|
43
|
+
assert_equal(19, @q.length)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_merge
|
47
|
+
@q1 = @q.class.new
|
48
|
+
@q2 = @q.class.new
|
49
|
+
|
50
|
+
20.times do | i |
|
51
|
+
@q1[i] = i
|
52
|
+
@q2[i+20] = i+20
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Assure that delete min works
|
57
|
+
def test_delete_min
|
58
|
+
assert_equal(nil, @q.delete_min, "Empty queue should pop nil")
|
59
|
+
@q["n1"] = 0
|
60
|
+
assert_equal(["n1", 0], @q.delete_min)
|
61
|
+
@q["n1"] = 0
|
62
|
+
@q["n2"] = -1
|
63
|
+
assert_equal(["n2", -1], @q.delete_min)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_delete_min_return_key
|
67
|
+
assert_equal(nil, @q.delete_min_return_key, "Empty queue should pop nil")
|
68
|
+
@q["n1"] = 0
|
69
|
+
assert_equal("n1", @q.delete_min_return_key)
|
70
|
+
@q["n1"] = 0
|
71
|
+
@q["n2"] = -1
|
72
|
+
assert_equal("n2", @q.delete_min_return_key)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_delete_min_return_priority
|
76
|
+
assert_equal(nil, @q.delete_min_return_priority, "Empty queue should pop nil")
|
77
|
+
@q["n1"] = 0
|
78
|
+
assert_equal(0, @q.delete_min_return_priority)
|
79
|
+
@q["n1"] = 0
|
80
|
+
@q["n2"] = -1
|
81
|
+
assert_equal(-1, @q.delete_min_return_priority)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_has_key?
|
85
|
+
assert(!@q.has_key?(1))
|
86
|
+
@q[1] = 1
|
87
|
+
assert(@q.has_key?(1))
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_empty?
|
91
|
+
assert_equal(true, @q.empty?, "Empty queue should return true on empty?")
|
92
|
+
@q["node1"] = 10
|
93
|
+
assert_equal(false, @q.empty?, "Filled queue should return false on empty?")
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_push
|
97
|
+
20.times do | i |
|
98
|
+
@q.push i, i+10
|
99
|
+
end
|
100
|
+
|
101
|
+
20.times do | i |
|
102
|
+
@q.push i, i
|
103
|
+
end
|
104
|
+
|
105
|
+
20.times do | i |
|
106
|
+
assert_equal([i, i], @q.delete_min)
|
107
|
+
end
|
108
|
+
|
109
|
+
assert_equal(nil, @q.delete_min)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_push_pop
|
113
|
+
20.times do | i |
|
114
|
+
@q.push i, i
|
115
|
+
end
|
116
|
+
|
117
|
+
20.times do | i |
|
118
|
+
assert_equal([i, i], @q.delete_min)
|
119
|
+
end
|
120
|
+
|
121
|
+
assert_equal(nil, @q.delete_min)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_push_decrease_pop
|
125
|
+
50.times do | i |
|
126
|
+
@q.push i, i
|
127
|
+
end
|
128
|
+
|
129
|
+
10.times do | i |
|
130
|
+
assert_equal([i, i], @q.delete_min)
|
131
|
+
end
|
132
|
+
|
133
|
+
10.times do | i |
|
134
|
+
@q[i+10] = i
|
135
|
+
end
|
136
|
+
|
137
|
+
10.times do | i |
|
138
|
+
assert_equal([i+10, i], @q.delete_min)
|
139
|
+
end
|
140
|
+
|
141
|
+
30.times do | i |
|
142
|
+
assert_equal([i+20, i+20], @q.delete_min)
|
143
|
+
end
|
144
|
+
|
145
|
+
assert_equal(nil, @q.delete_min)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_min_key
|
149
|
+
assert_equal(nil, @q.min_key)
|
150
|
+
@q["node1"] = 0
|
151
|
+
assert_equal("node1", @q.min_key)
|
152
|
+
@q["node2"] = 1
|
153
|
+
assert_equal("node1", @q.min_key)
|
154
|
+
@q["node3"] = -1
|
155
|
+
assert_equal("node3", @q.min_key)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_min_priority
|
159
|
+
assert_equal(nil, @q.min_priority)
|
160
|
+
@q["node1"] = 0
|
161
|
+
assert_equal(0, @q.min_priority)
|
162
|
+
@q["node2"] = 1
|
163
|
+
assert_equal(0, @q.min_priority)
|
164
|
+
@q["node3"] = -1
|
165
|
+
assert_equal(-1, @q.min_priority)
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_access
|
169
|
+
assert_equal(0, @q["node1"] = 0)
|
170
|
+
assert_equal(["node1", 0], @q.min)
|
171
|
+
assert_equal(1, @q["node2"] = 1)
|
172
|
+
assert_equal(1, @q["node2"])
|
173
|
+
assert_equal("node1", @q.min_key)
|
174
|
+
assert_equal(2, @q["node3"] = 2)
|
175
|
+
assert_equal(2, @q["node3"])
|
176
|
+
assert_equal("node1", @q.min_key)
|
177
|
+
assert_equal(-1, @q["node3"] = -1)
|
178
|
+
assert_equal(-1, @q["node3"])
|
179
|
+
assert_equal("node3", @q.min_key)
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_min
|
183
|
+
assert_equal(nil, @q.min)
|
184
|
+
@q["node1"] = 10
|
185
|
+
assert_equal(["node1", 10], @q.min)
|
186
|
+
@q["node2"] = 5
|
187
|
+
assert_equal(["node2", 5], @q.min)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_decrease_priority
|
191
|
+
|
192
|
+
20.times do | i |
|
193
|
+
@q.push i, i / 20.0
|
194
|
+
end
|
195
|
+
|
196
|
+
assert_equal([0, 0], @q.delete_min)
|
197
|
+
|
198
|
+
@q[10] = -1
|
199
|
+
@q[11] = -0.5
|
200
|
+
|
201
|
+
[10, 11, (1..9).to_a, (12..19).to_a, nil].flatten.each do | shall |
|
202
|
+
key, priority = *@q.delete_min
|
203
|
+
assert_equal(shall, key)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_increase_priority
|
208
|
+
20.times do | i |
|
209
|
+
@q[i] = i
|
210
|
+
end
|
211
|
+
@q[10] = 5
|
212
|
+
assert_equal([0,0], @q.delete_min)
|
213
|
+
assert_equal(10, @q[10] = 10)
|
214
|
+
assert_equal(20, @q[11] = 20)
|
215
|
+
assert_equal([1,1], @q.delete_min)
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_delete
|
219
|
+
@q[1] = 1
|
220
|
+
@q[2] = 2
|
221
|
+
@q[3] = 3
|
222
|
+
assert_equal(1, @q[1])
|
223
|
+
assert_equal([1,1], @q.min)
|
224
|
+
assert_equal([1,1], @q.delete(1))
|
225
|
+
assert_equal(nil, @q[1])
|
226
|
+
assert_equal([2,2], @q.min)
|
227
|
+
assert_equal(nil, @q.delete(1))
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_example_1
|
231
|
+
assert_equal(0, @q["node1"] = 0)
|
232
|
+
assert_equal(1, @q["node2"] = 1)
|
233
|
+
assert_equal("node1", @q.min_key)
|
234
|
+
assert_equal(0, @q[@q.min_key])
|
235
|
+
assert_equal(0, @q.min_priority)
|
236
|
+
|
237
|
+
@q["node2"] = -1
|
238
|
+
assert_equal(["node2", -1], @q.delete_min)
|
239
|
+
assert_equal(nil, @q["node2"])
|
240
|
+
@q["node3"] = 1
|
241
|
+
|
242
|
+
assert_equal(["node3", 1], @q.delete("node3"))
|
243
|
+
assert_equal(nil, @q.delete("node2"))
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_dup
|
247
|
+
('a'..'z').each do | n |
|
248
|
+
@q[n] = n[0]
|
249
|
+
end
|
250
|
+
qq = @q.dup
|
251
|
+
until @q.empty?
|
252
|
+
assert_equal(@q.delete_min, qq.delete_min)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_each
|
257
|
+
('a'..'z').each do | n |
|
258
|
+
@q[n] = n[0]
|
259
|
+
end
|
260
|
+
queue = ('a'..'z').inject([]) { | r, n | r << [n, n[0]] }
|
261
|
+
assert_equal(queue.sort, @q.to_a.sort)
|
262
|
+
end
|
263
|
+
|
264
|
+
extend self
|
265
|
+
end
|
266
|
+
|
267
|
+
class CPriorityQueueTest < Test::Unit::TestCase
|
268
|
+
include PriorityQueueTest
|
269
|
+
|
270
|
+
def setup
|
271
|
+
@q = CPriorityQueue.new
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_to_dot
|
275
|
+
5.times do | i |
|
276
|
+
@q.push "N#{i}", i
|
277
|
+
end
|
278
|
+
@q.delete_min
|
279
|
+
assert_equal(
|
280
|
+
['digraph fibonacci_heap {',
|
281
|
+
' NODE [label="N1 (1)",shape=box];',
|
282
|
+
' NODE [label="N3 (3)",shape=box];',
|
283
|
+
' NODE [label="N4 (4)",shape=box];',
|
284
|
+
' NODE -> NODE;',
|
285
|
+
' NODE -> NODE;',
|
286
|
+
' NODE [label="N2 (2)",shape=box];',
|
287
|
+
' NODE -> NODE;',
|
288
|
+
'}',''].join("\n"), @q.to_dot.gsub(/NODE[0-9]*/, 'NODE'))
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|
292
|
+
|
293
|
+
class PoorPriorityQueueTest < Test::Unit::TestCase
|
294
|
+
include PriorityQueueTest
|
295
|
+
|
296
|
+
def setup
|
297
|
+
@q = PoorPriorityQueue.new
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
class RubyPriorityQueueTest < Test::Unit::TestCase
|
303
|
+
include PriorityQueueTest
|
304
|
+
|
305
|
+
def setup
|
306
|
+
@q = RubyPriorityQueue.new
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_private_link_nodes
|
310
|
+
q = RubyPriorityQueue.new
|
311
|
+
q[0] = 0
|
312
|
+
q[1] = 1
|
313
|
+
tc = self
|
314
|
+
q.instance_eval do
|
315
|
+
n0 = @nodes[0]
|
316
|
+
n1 = @nodes[1]
|
317
|
+
n0.right = n0.left = n0
|
318
|
+
n1.right = n1.left = n1
|
319
|
+
tc.assert_equal(n0, link_nodes(n0, n1))
|
320
|
+
tc.assert_equal(n0.child, n1)
|
321
|
+
tc.assert_equal(n1.child, nil)
|
322
|
+
tc.assert_equal(n0.left, n0)
|
323
|
+
tc.assert_equal(n1.left, n1)
|
324
|
+
tc.assert_equal(n0.right, n0)
|
325
|
+
tc.assert_equal(n1.right, n1)
|
326
|
+
end
|
327
|
+
q = RubyPriorityQueue.new
|
328
|
+
q[0] = 0
|
329
|
+
q[1] = 1
|
330
|
+
q.instance_eval do
|
331
|
+
n0 = @nodes[0]
|
332
|
+
n1 = @nodes[1]
|
333
|
+
n0.right = n0.left = n0
|
334
|
+
n1.right = n1.left = n1
|
335
|
+
tc.assert_equal(n0, link_nodes(n1, n0))
|
336
|
+
tc.assert_equal(n0.child, n1)
|
337
|
+
tc.assert_equal(n1.child, nil)
|
338
|
+
tc.assert_equal(n0.left, n0)
|
339
|
+
tc.assert_equal(n1.left, n1)
|
340
|
+
tc.assert_equal(n0.right, n0)
|
341
|
+
tc.assert_equal(n1.right, n1)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
|
346
|
+
def test_private_delete_first
|
347
|
+
q = RubyPriorityQueue.new
|
348
|
+
q[0] = 0
|
349
|
+
q[1] = 1
|
350
|
+
q[2] = 2
|
351
|
+
tc = self
|
352
|
+
q.instance_eval do
|
353
|
+
2.times do
|
354
|
+
r = @rootlist
|
355
|
+
tc.assert_equal(r, delete_first)
|
356
|
+
tc.assert_equal(r.right, r)
|
357
|
+
tc.assert_equal(r.left, r)
|
358
|
+
tc.assert_not_equal(r, @rootlist.left)
|
359
|
+
tc.assert_not_equal(r, @rootlist.right)
|
360
|
+
end
|
361
|
+
r = @rootlist
|
362
|
+
tc.assert_equal(r, delete_first)
|
363
|
+
tc.assert_equal(r.right, r)
|
364
|
+
tc.assert_equal(r.left, r)
|
365
|
+
tc.assert_equal(nil, @rootlist)
|
366
|
+
|
367
|
+
tc.assert_equal(nil, delete_first)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|