gratr19 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README +335 -0
- data/examples/graph_self.rb +54 -0
- data/examples/module_graph.jpg +0 -0
- data/examples/module_graph.rb +12 -0
- data/examples/self_graph.jpg +0 -0
- data/examples/visualize.jpg +0 -0
- data/examples/visualize.rb +8 -0
- data/install.rb +49 -0
- data/lib/gratr.rb +42 -0
- data/lib/gratr/adjacency_graph.rb +230 -0
- data/lib/gratr/base.rb +34 -0
- data/lib/gratr/biconnected.rb +116 -0
- data/lib/gratr/chinese_postman.rb +123 -0
- data/lib/gratr/common.rb +74 -0
- data/lib/gratr/comparability.rb +92 -0
- data/lib/gratr/digraph.rb +115 -0
- data/lib/gratr/digraph_distance.rb +185 -0
- data/lib/gratr/dot.rb +90 -0
- data/lib/gratr/edge.rb +145 -0
- data/lib/gratr/graph.rb +314 -0
- data/lib/gratr/graph_api.rb +82 -0
- data/lib/gratr/import.rb +44 -0
- data/lib/gratr/labels.rb +103 -0
- data/lib/gratr/maximum_flow.rb +107 -0
- data/lib/gratr/rdot.rb +332 -0
- data/lib/gratr/search.rb +422 -0
- data/lib/gratr/strong_components.rb +127 -0
- data/lib/gratr/undirected_graph.rb +153 -0
- data/lib/gratr/version.rb +6 -0
- data/lib/priority-queue/benchmark/dijkstra.rb +171 -0
- data/lib/priority-queue/compare_comments.rb +49 -0
- data/lib/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
- data/lib/priority-queue/lib/priority_queue.rb +14 -0
- data/lib/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
- data/lib/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
- data/lib/priority-queue/lib/priority_queue/ruby_priority_queue.rb +525 -0
- data/lib/priority-queue/setup.rb +1551 -0
- data/lib/priority-queue/test/priority_queue_test.rb +371 -0
- data/tests/TestBiconnected.rb +53 -0
- data/tests/TestChinesePostman.rb +53 -0
- data/tests/TestComplement.rb +54 -0
- data/tests/TestDigraph.rb +333 -0
- data/tests/TestDigraphDistance.rb +138 -0
- data/tests/TestDot.rb +75 -0
- data/tests/TestEdge.rb +171 -0
- data/tests/TestInspection.rb +57 -0
- data/tests/TestMultiEdge.rb +57 -0
- data/tests/TestNeighborhood.rb +64 -0
- data/tests/TestProperties.rb +160 -0
- data/tests/TestSearch.rb +277 -0
- data/tests/TestStrongComponents.rb +85 -0
- data/tests/TestTriagulated.rb +137 -0
- data/tests/TestUndirectedGraph.rb +219 -0
- metadata +152 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2006 Shawn Patrick Garbett
|
3
|
+
# Copyright (c) 2002,2004,2005 by Horst Duchene
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
# are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice(s),
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of the Shawn Garbett nor the names of its contributors
|
14
|
+
# may be used to endorse or promote products derived from this software
|
15
|
+
# without specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
18
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
|
30
|
+
require 'gratr/adjacency_graph'
|
31
|
+
require 'gratr/search'
|
32
|
+
require 'gratr/biconnected'
|
33
|
+
require 'gratr/comparability'
|
34
|
+
require 'set'
|
35
|
+
|
36
|
+
module GRATR
|
37
|
+
class UndirectedGraph
|
38
|
+
include AdjacencyGraph
|
39
|
+
include Graph::Search
|
40
|
+
include Graph::Biconnected
|
41
|
+
include Graph::Comparability
|
42
|
+
|
43
|
+
def initialize(*params)
|
44
|
+
raise ArgumentError if params.any? do |p|
|
45
|
+
!(p.kind_of? GRATR::Graph or p.kind_of? Array)
|
46
|
+
end if self.class == GRATR::UndirectedGraph
|
47
|
+
super(*params)
|
48
|
+
end
|
49
|
+
|
50
|
+
# UndirectedGraph is by definition undirected, always returns false
|
51
|
+
def directed?() false; end
|
52
|
+
|
53
|
+
# Redefine degree (default was sum)
|
54
|
+
def degree(v) in_degree(v); end
|
55
|
+
|
56
|
+
# A vertex of an undirected graph is balanced by definition
|
57
|
+
def balanced?(v) true; end
|
58
|
+
|
59
|
+
# UndirectedGraph uses Edge for the edge class.
|
60
|
+
def edge_class() @parallel_edges ? GRATR::MultiEdge : GRATR::Edge; end
|
61
|
+
|
62
|
+
def remove_edge!(u, v=nil)
|
63
|
+
unless u.kind_of? GRATR::Arc
|
64
|
+
raise ArgumentError if @parallel_edges
|
65
|
+
u = edge_class[u,v]
|
66
|
+
end
|
67
|
+
super(u.reverse) unless u.source == u.target
|
68
|
+
super(u)
|
69
|
+
end
|
70
|
+
|
71
|
+
# A triangulated graph is an undirected perfect graph that every cycle of length greater than
|
72
|
+
# three possesses a chord. They have also been called chordal, rigid circuit, monotone transitive,
|
73
|
+
# and perfect elimination graphs.
|
74
|
+
#
|
75
|
+
# Implementation taken from Golumbic's, "Algorithmic Graph Theory and
|
76
|
+
# Perfect Graphs" pg. 90
|
77
|
+
def triangulated?
|
78
|
+
a = Hash.new {|h,k| h[k]=Set.new}; sigma=lexicograph_bfs
|
79
|
+
inv_sigma = sigma.inject({}) {|acc,val| acc[val] = sigma.index(val); acc}
|
80
|
+
sigma[0..-2].each do |v|
|
81
|
+
x = adjacent(v).select {|w| inv_sigma[v] < inv_sigma[w] }
|
82
|
+
unless x.empty?
|
83
|
+
u = sigma[x.map {|y| inv_sigma[y]}.min]
|
84
|
+
a[u].merge(x - [u])
|
85
|
+
end
|
86
|
+
return false unless a[v].all? {|z| adjacent?(v,z)}
|
87
|
+
end
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
def chromatic_number
|
92
|
+
return triangulated_chromatic_number if triangulated?
|
93
|
+
raise NotImplementedError
|
94
|
+
end
|
95
|
+
|
96
|
+
# An interval graph can have its vertices into one-to-one
|
97
|
+
# correspondence with a set of intervals F of a linearly ordered
|
98
|
+
# set (like the real line) such that two vertices are connected
|
99
|
+
# by an edge of G if and only if their corresponding intervals
|
100
|
+
# have nonempty intersection.
|
101
|
+
def interval?() triangulated? and complement.comparability?; end
|
102
|
+
|
103
|
+
# A permutation diagram consists of n points on each of two parallel
|
104
|
+
# lines and n straight line segments matchin the points. The intersection
|
105
|
+
# graph of the line segments is called a permutation graph.
|
106
|
+
def permutation?() comparability? and complement.comparability?; end
|
107
|
+
|
108
|
+
# An undirected graph is defined to be split if there is a partition
|
109
|
+
# V = S + K of its vertex set into a stable set S and a complete set K.
|
110
|
+
def split?() triangulated? and complement.triangulated?; end
|
111
|
+
|
112
|
+
private
|
113
|
+
# Implementation taken from Golumbic's, "Algorithmic Graph Theory and
|
114
|
+
# Perfect Graphs" pg. 99
|
115
|
+
def triangulated_chromatic_number
|
116
|
+
chi = 1; s= Hash.new {|h,k| h[k]=0}
|
117
|
+
sigma=lexicograph_bfs
|
118
|
+
inv_sigma = sigma.inject({}) {|acc,val| acc[val] = sigma.index(val); acc}
|
119
|
+
sigma.each do |v|
|
120
|
+
x = adjacent(v).select {|w| inv_sigma[v] < inv_sigma[w] }
|
121
|
+
unless x.empty?
|
122
|
+
u = sigma[x.map {|y| inv_sigma[y]}.min]
|
123
|
+
s[u] = [s[u], x.size-1].max
|
124
|
+
chi = [chi, x.size+1].max if s[v] < x.size
|
125
|
+
end
|
126
|
+
end; chi
|
127
|
+
end
|
128
|
+
|
129
|
+
end # UndirectedGraph
|
130
|
+
|
131
|
+
# This is a UndirectedGraph that allows for parallel edges, but does not
|
132
|
+
# allow loops
|
133
|
+
class UndirectedPseudoGraph < UndirectedGraph
|
134
|
+
def initialize(*params)
|
135
|
+
raise ArgumentError if params.any? do |p|
|
136
|
+
!(p.kind_of? Graph or p.kind_of? Array)
|
137
|
+
end
|
138
|
+
super(:parallel_edges, *params)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# This is a UndirectedGraph that allows for parallel edges and loops
|
143
|
+
class UndirectedMultiGraph < UndirectedGraph
|
144
|
+
def initialize(*params)
|
145
|
+
raise ArgumentError if params.any? do |p|
|
146
|
+
!(p.kind_of? Graph or p.kind_of? Array)
|
147
|
+
end
|
148
|
+
super(:parallel_edges, :loops, *params)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
end # GRATR
|
@@ -0,0 +1,171 @@
|
|
1
|
+
$:.unshift "~/lib/ruby"
|
2
|
+
require 'priority_queue/ruby_priority_queue'
|
3
|
+
require 'priority_queue/poor_priority_queue'
|
4
|
+
require 'priority_queue/c_priority_queue'
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
class Node
|
8
|
+
attr_reader :neighbours, :id
|
9
|
+
|
10
|
+
def initialize(id)
|
11
|
+
@neighbours = []
|
12
|
+
@id = id
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"(#{@id})"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Build a graph by adding nodes with random connections
|
25
|
+
|
26
|
+
# Return a random graph with an average degree of degree
|
27
|
+
def make_graph(nodes, degree)
|
28
|
+
nodes = Array.new(nodes) { | i | Node.new(i.to_s) }
|
29
|
+
nodes.each do | n |
|
30
|
+
(degree / 2).times do
|
31
|
+
true while (n1 = nodes[rand(nodes.length)]) == n
|
32
|
+
n.neighbours << nodes[rand(nodes.length)]
|
33
|
+
n1.neighbours << n
|
34
|
+
n.neighbours << n1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def draw_graph(nodes, out)
|
40
|
+
dot = [] << "graph g {"
|
41
|
+
nodes.each do | n1 |
|
42
|
+
dot << "N#{n1.id} [label='#{n1.id}'];"
|
43
|
+
n1.neighbours.each do | n2 |
|
44
|
+
dot << "N#{n1.id} -- N#{n2.id};" if n1.id <= n2.id
|
45
|
+
end
|
46
|
+
end
|
47
|
+
dot << "}"
|
48
|
+
|
49
|
+
# system "echo '#{dot}' | neato -Gepsilon=0.001 -Goverlap=scale -Gsplines=true -Gsep=.4 -Tps -o #{out}"
|
50
|
+
system "echo '#{dot}' | neato -Gepsilon=0.05 -Goverlap=scale -Gsep=.4 -Tps -o #{out}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def dijkstra(start_node, queue_klass)
|
54
|
+
# Priority Queue with unfinished nodes
|
55
|
+
active = queue_klass.new
|
56
|
+
# Distances for all nodes
|
57
|
+
distances = Hash.new { 1.0 / 0.0 }
|
58
|
+
# Parent pointers describing shortest paths for all nodes
|
59
|
+
parents = Hash.new
|
60
|
+
|
61
|
+
# Initialize with start node
|
62
|
+
active[start_node] = 0
|
63
|
+
until active.empty?
|
64
|
+
u, distance = active.delete_min
|
65
|
+
distances[u] = distance
|
66
|
+
d = distance + 1
|
67
|
+
u.neighbours.each do | v |
|
68
|
+
next unless d < distances[v] # we can't relax this one
|
69
|
+
active[v] = distances[v] = d
|
70
|
+
parents[v] = u
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
srand
|
76
|
+
|
77
|
+
sizes = Array.new(4) { | base | Array.new(9) { | mult | (mult+1) * 10**(base+2) } }.flatten
|
78
|
+
degrees = [2, 4, 16]
|
79
|
+
degrees = [4, 16]
|
80
|
+
degrees = [16]
|
81
|
+
queues = [ CPriorityQueue, PoorPriorityQueue, RubyPriorityQueue ]
|
82
|
+
queues = [ CPriorityQueue, RubyPriorityQueue ]
|
83
|
+
|
84
|
+
max_time = 400
|
85
|
+
ignore = Hash.new
|
86
|
+
|
87
|
+
repeats = 5
|
88
|
+
|
89
|
+
|
90
|
+
STDOUT.sync = true
|
91
|
+
|
92
|
+
results = Hash.new { | h, k | h[k] =
|
93
|
+
Hash.new { | h1, k1 | h1[k1] = Hash.new { 0 }
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
Benchmark.bm(30) do | b |
|
98
|
+
sizes.each do | size |
|
99
|
+
break if !ignore.empty? and ignore.values.inject(true) { | r, v | r and v }
|
100
|
+
puts
|
101
|
+
puts "Testing with graphs of size #{size}"
|
102
|
+
degrees.each do | degree |
|
103
|
+
repeats.times do | r |
|
104
|
+
nodes = make_graph(size, degree)
|
105
|
+
queues.each do | queue |
|
106
|
+
next if ignore[queue]
|
107
|
+
GC.start
|
108
|
+
results[queue][degree][size] += (b.report("#{queue}: #{size} (#{degree})") do dijkstra(nodes[1], queue) end).real
|
109
|
+
end
|
110
|
+
end
|
111
|
+
queues.each do | queue |
|
112
|
+
ignore[queue] ||= ((results[queue][degree][size] / repeats) > max_time)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
indices = queues.map { | q | degrees.map { | d | %&"#{q} (Graph of Degree: #{d})"& } }.flatten
|
117
|
+
File.open("results.csv", "wb") do | f |
|
118
|
+
f.puts "size\t" + indices.join("\t")
|
119
|
+
sizes.each do | size |
|
120
|
+
f.puts "#{size}\t" + queues.map { | q | degrees.map { | d |
|
121
|
+
(results[q][d].has_key?(size) and results[q][d][size] > 0.0) ? results[q][d][size] / repeats : "''"
|
122
|
+
} }.join("\t")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
File.open("results.gp", 'wb') do | f |
|
127
|
+
lines = []
|
128
|
+
indices.each_with_index do | t, i |
|
129
|
+
lines << " 'results.csv' using 1:#{i+2} with lines title #{t}"
|
130
|
+
end
|
131
|
+
f.puts "set term png"
|
132
|
+
f.puts "set out 'results.png'"
|
133
|
+
f.puts "set xlabel 'Number of nodes'"
|
134
|
+
f.puts "set ylabel 'Time in seconds (real)'"
|
135
|
+
f.puts "set logscale xy"
|
136
|
+
f.puts "set title 'Dijkstras Shortest Path Algorithm using different PQ Implementations'"
|
137
|
+
f.puts "plot \\"
|
138
|
+
f.puts lines.join(",\\\n")
|
139
|
+
end
|
140
|
+
system "gnuplot results.gp"
|
141
|
+
|
142
|
+
queues.each do | q |
|
143
|
+
File.open("result-#{q}.gp", 'wb') do | f |
|
144
|
+
lines = []
|
145
|
+
degrees.map { | d | %&"#{q} (Graph of Degree: #{d})"& }.flatten.each do | t |
|
146
|
+
lines << " 'results.csv' using 1:#{indices.index(t)+2} with lines title #{t}"
|
147
|
+
end
|
148
|
+
f.puts "set term png"
|
149
|
+
f.puts "set out 'result-#{q}.png'"
|
150
|
+
f.puts "set xlabel 'Number of nodes'"
|
151
|
+
f.puts "set ylabel 'Time in seconds (real)'"
|
152
|
+
f.puts "set logscale xy"
|
153
|
+
f.puts "set title 'Dijkstras Shortest Path Algorithm on Networks of different degrees'"
|
154
|
+
f.puts "plot \\"
|
155
|
+
f.puts lines.join(",\\\n")
|
156
|
+
end
|
157
|
+
system "gnuplot result-#{q}.gp"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
__END__
|
163
|
+
|
164
|
+
nodes = make_graph(100, 4)
|
165
|
+
draw_graph(nodes, "100-4.ps")
|
166
|
+
nodes = make_graph(100, 10)
|
167
|
+
draw_graph(nodes, "100-10.ps")
|
168
|
+
nodes = make_graph(10, 10)
|
169
|
+
draw_graph(nodes, "10-10.ps")
|
170
|
+
nodes = make_graph(1000, 2)
|
171
|
+
draw_graph(nodes, "1000-2.ps")
|
@@ -0,0 +1,49 @@
|
|
1
|
+
c_file = File.read("ext/priority_queue/CPriorityQueue/priority_queue.c")
|
2
|
+
rb_file = File.read("lib/priority_queue/ruby_priority_queue.rb")
|
3
|
+
|
4
|
+
c_comments = Hash.new { "" }
|
5
|
+
|
6
|
+
c_file.scan(%r(/\*(.*?)\*/\s*static\s+\w+\s*pq_(\w+)\(.*?\))m).each do | match |
|
7
|
+
c_comments[match[1]] = match[0].gsub(%r(\n\s*\* {0,1})m, "\n").strip
|
8
|
+
end
|
9
|
+
|
10
|
+
rb_comments = Hash.new { "" }
|
11
|
+
|
12
|
+
rb_file.scan(%r(((?:\n\s*#[^\n]*)*)\s*def\s+(\w+))m).each do | match |
|
13
|
+
rb_comments[match[1]] = match[0].gsub(%r(\n\s*# {0,1})m, "\n").strip
|
14
|
+
end
|
15
|
+
|
16
|
+
add_comments = Hash.new
|
17
|
+
|
18
|
+
(rb_comments.keys + c_comments.keys).uniq.each do | key |
|
19
|
+
#next if rb_comments[key].gsub(/\s+/m, " ") == c_comments[key].gsub(/\s+/m, " ")
|
20
|
+
if c_comments[key].empty?
|
21
|
+
add_comments[key] = rb_comments[key]
|
22
|
+
elsif rb_comments[key].empty?
|
23
|
+
add_comments[key] = c_comments[key]
|
24
|
+
elsif rb_comments[key] != c_comments[key]
|
25
|
+
|
26
|
+
puts key
|
27
|
+
puts "Ruby"
|
28
|
+
puts rb_comments[key]
|
29
|
+
puts "C"
|
30
|
+
puts c_comments[key]
|
31
|
+
puts
|
32
|
+
puts "Choose [c,r]"
|
33
|
+
1 until /^([cr])/ =~ gets
|
34
|
+
add_comments[key] = ($1 == "c" ? c_comments : rb_comments)[key]
|
35
|
+
puts "-" * 80
|
36
|
+
puts
|
37
|
+
else
|
38
|
+
add_comments[key] = rb_comments[key]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
File.open("lib/priority_queue/ruby_priority_queue.new.rb", "wb") do | o |
|
44
|
+
o <<
|
45
|
+
rb_file.gsub(%r(((?:\n\s*#[^\n]*)*)(\s*def\s+(\w+)))m) do | match |
|
46
|
+
name, all = $3, $2
|
47
|
+
"\n" + (add_comments[name].gsub(/^/, "#")) + all
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# A priority queue implementation.
|
2
|
+
# This extension contains two implementations, a c extension and a pure ruby
|
3
|
+
# implementation. When the compiled extension can not be found, it falls back
|
4
|
+
# to the pure ruby extension.
|
5
|
+
#
|
6
|
+
# See CPriorityQueue and RubyPriorityQueue for more information.
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'priority_queue/CPriorityQueue'
|
10
|
+
PriorityQueue = CPriorityQueue
|
11
|
+
rescue LoadError # C Version could not be found, try ruby version
|
12
|
+
require 'priority_queue/ruby_priority_queue'
|
13
|
+
PriorityQueue = RubyPriorityQueue
|
14
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "priority_queue/CPriorityQueue"
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# A Poor mans Priority Queue. (Very inefficent but minimal implemention).
|
2
|
+
class PoorPriorityQueue < Hash
|
3
|
+
def push(object, priority)
|
4
|
+
self[object] = priority
|
5
|
+
end
|
6
|
+
|
7
|
+
def min
|
8
|
+
return nil if self.empty?
|
9
|
+
min_k = self.keys.first
|
10
|
+
min_p = self[min_k]
|
11
|
+
self.each do | k, p |
|
12
|
+
min_k, min_p = k, p if p < min_p
|
13
|
+
end
|
14
|
+
[min_k, min_p]
|
15
|
+
end
|
16
|
+
|
17
|
+
def min_key
|
18
|
+
min[0] rescue nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def min_priority
|
22
|
+
min[1] rescue nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def delete_min
|
26
|
+
return nil if self.empty?
|
27
|
+
min_k, min_p = *min
|
28
|
+
self.delete(min_k)
|
29
|
+
[min_k, min_p]
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete_min_return_key
|
33
|
+
delete_min[0] rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete_min_return_priority
|
37
|
+
delete_min[1] rescue nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(object)
|
41
|
+
return nil unless self.has_key?(object)
|
42
|
+
result = [object, self[object]]
|
43
|
+
super
|
44
|
+
result
|
45
|
+
end
|
46
|
+
end
|