# Documentation: https://github.com/monzita/algorithmix/wiki/PriorityQueue module Algorithmix module DataStructure module Generic class PriorityQueue attr_reader :binary_heap # Creates a new priority queue. # # @param obj [#to_a] can be any object, which responds to #to_a method # @kwarg copy [true, false] if set to true, makes a copy of content of the given object # @kwarg min [true, false] sets the main property of the new priority queue. By default max priority queue is created. # @raise ArgumentError, if given object doesn't respond to to_a method. # @return [PriorityQueue] def initialize(obj = nil, copy: false, min: false) @binary_heap = Heap::BinaryHeap.new(obj, copy: copy, min: min) @max = min ? false : true end # Assigns content of an object, to content of the queue. # # @param obj [#to_a] # @kwarg copy [true, false] # @raise ArgumentError # @return self object [PriorityQeue] def assign(obj, copy: false) @binary_heap.assign(obj, copy: copy) self end # Inserts a value in the queue. # # @param value # @return [PriorityQueue] self object def push(value) @binary_heap.insert(value) self end # (see #push) def << push(value) end # Removes the element with highest or lowest priority of the queue. # # @raise Algorithmix::EmptyContainerError, if the queue is empty. # @return element with the highest or lowest priority def pop raise EmptyContainerError, "The priority queue is empty." if @binary_heap.empty? @binary_heap.extract end # Returns the element with the highest or lowest priority without removing it from the queue. def front @binary_heap.top end # Returns number of elements in the queue. def size @binary_heap.size end # (see #size) def length @binary_heap.size end # Returns information for the content of the queue - are there any elements, or no. def empty? @binary_heap.empty? end # Comapres contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a PriorityQueue. # @return [true, false] true if contents are equal, false otherwise def ==(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#== for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) to_a == priority_queue.to_a end # (see #==) def eql?(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#eql? for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self == priority_queue end # Comapres contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a PriorityQueue. # @return [true, false] true if contents are different, false otherwise def !=(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#!= for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) to_a != priority_queue.to_a end # (see #!=) def diff?(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#diff? for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self != priority_queue end # Comapres contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a PriorityQueue. # @return 1 if content of the queue is > content of the given queue, 0 if contents are euqal, -1 if content of the given queue is > content of the queue def <=>(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#<=> for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) to_a <=> priority_queue.to_a end # Converts content of the queue to an array. # # @return array with elements of the queue def to_a @binary_heap.to_a end # Clears content of the queue. # # @return [PriorityQueue] self object def clear @binary_heap.clear self end # Concatenates contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] a new priority queue def +(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#+ for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) PriorityQueue.new(@binary_heap + priority_queue.send(:binary_heap), min: !@max) end # (see #+) def concat(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#concat for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self + priority_queue end # (see #+) def merge(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#merge for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self + priority_queue end # Concatenates contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] self object def concat!(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#concat! for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) @binary_heap.concat!(priority_queue.send(:binary_heap)) self end # Concatenates contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] self object def merge!(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#merge! for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) @binary_heap.merge!(priority_queue.send(:binary_heap)) self end # Unites contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] a new priority queue def |(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#| for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) PriorityQueue.new(@binary_heap | priority_queue.send(:binary_heap), min: !@max) end # (see #|) def union(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#union for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self | priority_queue end # Unites contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] self object def union!(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#union! for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) @binary_heap = @binary_heap | priority_queue.send(:binary_heap) self end # Finds the intersection of contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] a new priority queue def &(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#& for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) PriorityQueue.new(@binary_heap & priority_queue.send(:binary_heap), min: !@max) end # (see #&) def intersect(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#intersect for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self & priority_queue end # Finds the intersection contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] self object def intersect!(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#intersect! for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) @binary_heap.intersect!(priority_queue.send(:binary_heap)) self end # Finds the difference of contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] a new priority queue def -(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#- for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) PriorityQueue.new(@binary_heap - priority_queue.send(:binary_heap), min: !@max) end # (see #-) def difference(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#difference for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self - priority_queue end # Finds the difference of contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] self object def difference!(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#difference! for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) @binary_heap.difference!(priority_queue.send(:binary_heap)) self end # Finds the symmetric difference of contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] a new priority queue def ^(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#^ for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) PriorityQueue.new(@binary_heap ^ priority_queue.send(:binary_heap), min: !@max) end # (see #^) def symmetric_difference(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#symmetric_difference for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) self ^ priority_queue end # Finds the symmetric difference of contents of the queue and a queue given as argument. # # @param priority_queue [PriorityQueue] # @raise ArgumentError, if given object is not a priority queue # @return [PriorityQueue] self object def symmetric_difference!(priority_queue) raise ArgumentError, "Undefined method PriorityQueue#symmetric_difference! for #{priority_queue}:#{priority_queue.class}" unless priority_queue.is_a?(PriorityQueue) @binary_heap.symmetric_difference!(priority_queue.send(:binary_heap)) self end # Filters elements of the queue by given condition. # # @param &block # @return [PriorityQueue] a new priority queue def select(&block) PriorityQueue.new(@binary_heap.select { |e| block.call(e) }, min: !@max) end # Filters elements of the queue by given condition. # # @param &block # @return [PriorityQueue] self object def select!(&block) @binary_heap.select! { |e| block.call(e) } self end # (see #select) def filter(&block) select(&block) end # (see #select!) def filter!(&block) select!(&block) end # (see #select) def find_all(&block) select(&block) end # (see #select!) def find_all!(&block) select!(&block) end # Applies a function to each element of the queue. # # @param &block # @return [PriorityQueue] a new priority queue def map(&block) PriorityQueue.new(@binary_heap.map { |e| block.call(e)}, min: !@max) end # Applies a function to each element of the queue. # # @param &block # @return [PriorityQueue] self object def map!(&block) @binary_heap.map! { |e| block.call(e) } self end # (see #map) def apply(&block) map(&block) end # (see #map!) def apply!(&block) map!(&block) end private :binary_heap end end end end