Untitled
unknown
ruby
4 years ago
13 kB
8
Indexable
def min_set_size(arr)
min_size = (arr.length + 1) / 2
q = RubyPriorityQueue.new
arr.each do |num|
if q.has_key?(num)
q.push(num, q[num] - 1)
else
q.push(num, -1)
end
end
count = 0
size = 0
while count < min_size
if q.empty?
return size
else
count += -(q.delete_min[1])
size += 1
end
end
size
end
# Pure ruby Priority Queue
class RubyPriorityQueue
include Enumerable
private
#
def link_nodes(b1, b2)
return link_nodes(b2, b1) if b2.priority < b1.priority
b2.parent = b1
child = b1.child
b1.child = b2
if child
b2.left = child.left
b2.left.right = b2
b2.right = child
child.left = b2
else
b2.left = b2
b2.right = b2
end
b1.degree += 1
b2.mark = false # TODO: Check if this is correct, or if b1 should be marked as false
return b1
end
# Does not change length
def delete_first
return nil unless @rootlist
result = @rootlist
if result == result.right
@min = @rootlist = nil
else
@rootlist = result.right
@rootlist.left = result.left
@rootlist.left.right = @rootlist
result.right = result.left = result
end
return result;
end
def cut_node(n)
return self unless n.parent
n.parent.degree -= 1
if n.parent.child == n
if n.right == n
n.parent.child = nil
else
n.parent.child = n.right;
end
end
n.parent = nil
n.right.left = n.left
n.left.right = n.right
n.right = @rootlist
n.left = @rootlist.left
@rootlist.left.right = n
@rootlist.left = n
n.mark = false
return self
end
# Does not change length
def insert_tree(tree)
if @rootlist == nil
@rootlist = @min = tree
else
l = @rootlist.left
l.right = tree
@rootlist.left = tree
tree.left = l
tree.right = @rootlist
@min = tree if tree.priority < @min.priority
end
self
end
def consolidate
return self if self.empty?
array_size = (2.0 * Math.log(self.length) / Math.log(2) + 1.0).ceil
tree_by_degree = Array.new(array_size)
while n = delete_first
while n1 = tree_by_degree[n.degree]
tree_by_degree[n.degree] = nil;
n = link_nodes(n, n1);
end
tree_by_degree[n.degree] = n;
end
@rootlist = @min = nil;
tree_by_degree.each do | tree |
next unless tree
insert_tree(tree)
end
self
end
# Node class used internally
class Node # :nodoc:
attr_accessor :parent, :left, :right, :key, :priority, :degree, :mark
attr_reader :child
def child=(c)
raise "Circular Child" if c == self
raise "Child is neighbour" if c == self.right
raise "Child is neighbour" if c == self.left
@child = c
end
def to_dot(only_down = false, known_nodes = [])
p known_nodes.map { | n | n.dot_id }
p self.dot_id
result = []
if only_down
raise "Circular #{caller.inspect}" if known_nodes.include?(self)
known_nodes << self
result << "#{dot_id} [label=\"#{@key}: #{@priority}\"];"
l = " "
#l << "#{@left.dot_id} <- #{dot_id}; " if @left
l << "#{dot_id} -> #{@left.dot_id} [constraint=false]; " if @left and @left.dot_id < self.dot_id
l << "#{dot_id} -> #{@right.dot_id} [constraint=false];\t\t\t\t/*neighbours*/" if @right and @right.dot_id <= self.dot_id
result << l
result << " #{dot_id} -> #{@child.dot_id}; //child" if @child
result << @child.to_dot(false, known_nodes) if @child
else
n = self
begin
result.concat(n.to_dot(true, known_nodes))
n = n.right
end while n != self
end
result.flatten.map{|r| " " << r}
end
def dot_id
"N#{@key}"
end
def initialize(key, priority)
@key = key; @priority = priority; @degree = 0
end
end
public
# Returns the number of elements of the queue.
#
# q = PriorityQueue.new
# q.length #=> 0
# q[0] = 1
# q.length #=> 1
attr_reader :length
# Create a new, empty PriorityQueue
def initialize
@nodes = Hash.new
@rootlist = nil
@min = nil
@length = 0
end
# Print a priority queue as a dot-graph. The output can be fed to dot from the
# vizgraph suite to create a tree depicting the internal datastructure.
def to_dot
r = ["digraph fibheap {"]
#r << @rootlist.to_dot.join("\n") if @rootlist
r << "ROOT -> #{@rootlist.dot_id};" if @rootlist
@nodes.to_a.sort.each do | (_, n) |
r << " #{n.dot_id} [label=\"#{n.key}: #{n.priority}\"];"
r << " #{n.dot_id} -> #{n.right.dot_id} [constraint=false];" if n.right# and n.dot_id < n.right.dot_id
r << " #{n.dot_id} -> #{n.left.dot_id} [constraint=false];" if n.left #and n.dot_id < n.left.dot_id
r << " #{n.dot_id} -> #{n.child.dot_id}" if n.child
end
r << "}"
r.join("\n")
r
end
# Call dot and gv displaying the datstructure
def display_dot
puts to_dot
system "echo '#{to_dot}' | twopi -Tps -Groot=ROOT -Goverlap=false> /tmp/dotfile.ps; gv /tmp/dotfile.ps"
end
# call-seq:
# [key] = priority
# change_priority(key, priority)
# push(key, priority)
#
# Set the priority of a key.
#
# q = PriorityQueue.new
# q["car"] = 50
# q["train"] = 50
# q["bike"] = 10
# q.min #=> ["bike", 10]
# q["car"] = 0
# q.min #=> ["car", 0]
def change_priority(key, priority)
return push(key, priority) unless @nodes[key]
n = @nodes[key]
if n.priority < priority # Priority was increased. Remove the node and reinsert.
self.delete(key)
self.push(key, priority);
return self
end
n.priority = priority;
@min = n if n.priority < @min.priority
return self if !n.parent or n.parent.priority <= n.priority # Already in rootlist or bigger than parent
begin # Cascading Cuts
p = n.parent
cut_node(n)
n = p
end while n.mark and n.parent
n.mark = true if n.parent
self
end
# Add an object to the queue.
def push(key, priority)
return change_priority(key, priority) if @nodes[key]
@nodes[key] = node = Node.new(key, priority)
@min = node if !@min or priority < @min.priority
if not @rootlist
@rootlist = node
node.left = node.right = node
else
node.left = @rootlist.left
node.right = @rootlist
@rootlist.left.right = node
@rootlist.left = node
end
@length += 1
self
end
# Returns true if the array is empty, false otherwise.
def empty?
@rootlist.nil?
end
# call-seq:
# [key] -> priority
#
# Return the priority of a key or nil if the key is not in the queue.
#
# q = PriorityQueue.new
# (0..10).each do | i | q[i.to_s] = i end
# q["5"] #=> 5
# q[5] #=> nil
def [](key)
@nodes[key] and @nodes[key].priority
end
# call-seq:
# has_key? key -> boolean
#
# Return false if the key is not in the queue, true otherwise.
#
# q = PriorityQueue.new
# (0..10).each do | i | q[i.to_s] = i end
# q.has_key("5") #=> true
# q.has_key(5) #=> false
def has_key?(key)
@nodes.has_key?(key)
end
alias :[]= :push
# Call the given block with each [key, priority] pair in the queue
#
# Beware: Changing the queue in the block may lead to unwanted behaviour and
# even infinite loops.
def each
@nodes.each do | key, node |
yield(key, node.priority)
end
end
# call-seq:
# min -> [object, priority]
#
# Return the pair [object, priority] with minimal priority or nil when the
# queue is empty.
#
# q = PriorityQueue.new
# q["a"] = 10
# q["b"] = 20
# q.min #=> ["a", 10]
# q.delete_min #=> ["a", 10]
# q.min #=> ["b", 20]
# q.delete_min #=> ["b", 20]
# q.min #=> nil
def min
[@min.key, @min.priority] rescue nil
end
# call-seq:
# min_key -> object
#
# Return the key that has the minimal priority or nil when the queue is empty.
#
# q = PriorityQueue.new
# q["a"] = 10
# q["b"] = 20
# q.min_key #=> "a"
# q.delete_min #=> ["a", 10]
# q.min_key #=> "b"
# q.delete_min #=> ["b", 20]
# q.min_key #=> nil
def min_key
@min.key rescue nil
end
# call-seq:
# min_priority -> priority
#
# Return the minimal priority or nil when the queue is empty.
#
# q = PriorityQueue.new
# q["a"] = 10
# q["b"] = 20
# q.min_priority #=> 10
# q.delete_min #=> ["a", 10]
# q.min_priority #=> 20
# q.delete_min #=> ["b", 20]
# q.min_priority #=> nil
def min_priority
@min.priority rescue nil
end
# call-seq:
# delete(key) -> [key, priority]
# delete(key) -> nil
#
# Delete a key from the priority queue. Returns nil when the key was not in
# the queue and [key, priority] otherwise.
#
# q = PriorityQueue.new
# (0..10).each do | i | q[i.to_s] = i end
# q.delete(5) #=> ["5", 5]
# q.delete(5) #=> nil
def delete(key)
return nil unless n = @nodes.delete(key)
if n.child
c = n.child
e = n.child
begin
r = c.right
cut_node(c)
c = r
end while c != e
end
cut_node(n) if n.parent
if n == n.right
@min = nil;
@rootlist = nil;
else
@rootlist = n.right if @rootlist == n
if @min == n
n1 = n.right
@min = n1
begin
@min = n1 if n1.priority < @min.priority
n1 = n1.right
end while(n1 != n);
end
n.right.left = n.left
n.left.right = n.right
n.left = n
n.right = n
end
@length -= 1
return [n.key, n.priority]
end
# call-seq:
# delete_min_return_key -> key
#
# Delete key with minimal priority and return the key
#
# q = PriorityQueue.new
# q["a"] = 1
# q["b"] = 0
# q.delete_min_return_key #=> "b"
# q.delete_min_return_key #=> "a"
# q.delete_min_return_key #=> nil
def delete_min_return_key
delete_min[0] rescue nil
end
# call-seq:
# delete_min_return_priority -> priority
#
# Delete key with minimal priority and return the priority value
#
# q = PriorityQueue.new
# q["a"] = 1
# q["b"] = 0
# q.delete_min_return_priority #=> 0
# q.delete_min_return_priority #=> 1
# q.delete_min_return_priority #=> nil
def delete_min_return_priority
delete_min[1] rescue nil
end
# call-seq:
# delete_min -> [key, priority]
#
# Delete key with minimal priority and return [key, priority]
#
# q = PriorityQueue.new
# q["a"] = 1
# q["b"] = 0
# q.delete_min #=> ["b", 0]
# q.delete_min #=> ["a", 1]
# q.delete_min #=> nil
def delete_min
return nil if self.empty?
result = self.min
@nodes.delete(@min.key)
if @length == 1
@rootlist = @min = nil
@length = 0
else
min = @min
if @min == @rootlist # If the rootlist is anchored at the minimum, shift to the right
if @rootlist == @rootlist.right
@rootlist = @min = nil
else
@rootlist = @min = @min.right
end
end
min.left.right = min.right;
min.right.left = min.left;
min.left = min.right = min;
if min.child
# Kinder und Eltern trennen, Markierung aufheben
n = min.child;
begin
n.parent = nil;
n.mark = false;
n = n.right;
end while n != min.child
# Kinder einfügen
if @rootlist
l1 = @rootlist.left
l2 = n.left
l1.right = n
n.left = l1
l2.right = @rootlist
@rootlist.left = l2
else
@rootlist = n
end
end
# Größe anpassen
@length -= 1
# Wieder aufhübschen
consolidate
end
result
end
# Returns a string representation of the priority queue.
def inspect
"<PriorityQueue: #{@nodes.map{|(_, n)| [n.key, n.priority]}.sort_by{|(_,p)|p}.inspect}>"
end
def initialize_copy(copy)
copy_nodes = @nodes
@nodes = {}
copy_nodes.each do | (_, cn) |
n = @nodes[cn.key] = Node.new(cn.key, cn.priority)
n.mark = cn.mark
n.degree = cn.degree
end
copy_nodes.each do | (_, cn) |
n = @nodes[cn.key]
n.left = @nodes[cn.left.key] if cn.left
n.right = @nodes[cn.right.key] if cn.right
n.parent = @nodes[cn.parent.key] if cn.parent
n.child = @nodes[cn.child.key] if cn.child
end
@rootlist = @nodes[@rootlist.key] if @rootlist
@min = @nodes[@min.key] if @min
self
end
endEditor is loading...