lib/d_heap.rb in d_heap-0.5.0 vs lib/d_heap.rb in d_heap-0.6.0

- old
+ new

@@ -8,41 +8,104 @@ # # The _d_-ary heap data structure is a generalization of the binary heap, in which # the nodes have _d_ children instead of 2. This allows for "decrease priority" # operations to be performed more quickly with the tradeoff of slower delete # minimum. Additionally, _d_-ary heaps can have better memory cache behavior than -# binary heaps, allowing them to run more quickly in practice despite slower +# binary heaps, allowing them to pop more quickly in practice despite slower # worst-case time complexity. # +# Although _d_ can be configured when creating the heap, it's usually best to +# keep the default value of 4, because d=4 gives the smallest coefficient for +# <tt>(d + 1) log n / log d</tt> result. As always, use benchmarks for your +# particular use-case. +# +# @example Basic push, peek, and pop +# # create some example objects to place in our heap +# Task = Struct.new(:id, :time) do +# def to_f; time.to_f end +# end +# t1 = Task.new(1, Time.now + 5*60) +# t2 = Task.new(2, Time.now + 50) +# t3 = Task.new(3, Time.now + 60) +# t4 = Task.new(4, Time.now + 5) +# +# # create the heap +# require "d_heap" +# heap = DHeap.new +# +# # push with an explicit score (which might be extrinsic to the value) +# heap.push t1, t1.to_f +# +# # the score will be implicitly cast with Float, so any object with #to_f +# heap.push t2, t2 +# +# # if the object has an intrinsic score via #to_f, "<<" is the simplest API +# heap << t3 << t4 +# +# # pop returns the lowest scored item, and removes it from the heap +# heap.pop # => #<struct Task id=4, time=2021-01-17 17:02:22.5574 -0500> +# heap.pop # => #<struct Task id=2, time=2021-01-17 17:03:07.5574 -0500> +# +# # peek returns the lowest scored item, without removing it from the heap +# heap.peek # => #<struct Task id=3, time=2021-01-17 17:03:17.5574 -0500> +# heap.pop # => #<struct Task id=3, time=2021-01-17 17:03:17.5574 -0500> +# +# # pop_lte handles the common "h.pop if h.peek_score < max" pattern +# heap.pop_lte(Time.now + 65) # => nil +# +# # the heap size can be inspected with size and empty? +# heap.empty? # => false +# heap.size # => 1 +# heap.pop # => #<struct Task id=1, time=2021-01-17 17:07:17.5574 -0500> +# heap.empty? # => true +# heap.size # => 0 +# +# # popping from an empty heap returns nil +# heap.pop # => nil +# class DHeap - alias deq pop - alias enq push - alias first peek - alias pop_below pop_lt + alias deq pop + alias shift pop + alias next pop + alias pop_all_lt pop_all_below + alias pop_below pop_lt - alias length size - alias count size + alias enq push - # ruby 3.0+ (2.x can just use inherited initialize_clone) - if Object.instance_method(:initialize_clone).arity == -1 - # @!visibility private - def initialize_clone(other, freeze: nil) - __init_clone__(other, freeze ? true : freeze) - end + alias first peek + + alias length size + alias count size + + # Initialize a _d_-ary min-heap. + # + # @param d [Integer] Number of children for each parent node. + # Higher values generally speed up push but slow down pop. + # If all pushes are popped, the default is probably best. + # @param capacity [Integer] initial capacity of the heap. + def initialize(d: DEFAULT_D, capacity: DEFAULT_CAPA) # rubocop:disable Naming/MethodParameterName + __init_without_kw__(d, capacity) end # Consumes the heap by popping each minumum value until it is empty. # # If you want to iterate over the heap without consuming it, you will need to # first call +#dup+ # + # @param with_score [Boolean] if scores shoul also be yielded + # # @yieldparam value [Object] each value that would be popped + # @yieldparam score [Numeric] each value's score, if +with_scores+ is true # # @return [Enumerator] if no block is given # @return [nil] if a block is given - def each_pop - return to_enum(__method__) unless block_given? - yield pop until empty? + def each_pop(with_scores: false) + return to_enum(__method__, with_scores: with_scores) unless block_given? + if with_scores + yield(*pop_with_score) until empty? + else + yield pop until empty? + end nil end end