Code for the Advent of Code event
aoc advent-of-code
at main 79 lines 1.6 kB view raw
1# frozen_string_literal: true 2 3class PriorityQueue 4 include Enumerable 5 6 class Element 7 include Comparable 8 9 attr_accessor :value, :priority 10 11 def initialize(value, priority) 12 @value, @priority = value, priority 13 end 14 15 def <=>(other) 16 @priority <=> other.priority 17 end 18 end 19 20 def initialize 21 @elements = [nil] 22 end 23 24 def size 25 @elements.size - 1 26 end 27 28 def each(&) 29 @elements.drop(1).each(&) 30 end 31 32 def empty? 33 size == 0 34 end 35 36 def <<(element) 37 @elements << element 38 bubble_up(@elements.size - 1) 39 end 40 41 def enqueue(value, priority = nil) 42 value = Element.new(value, priority) if priority 43 self << value 44 end 45 46 def dequeue 47 exchange(1, @elements.size - 1) 48 element = @elements.pop.tap { bubble_down(1) } 49 return element.value if element.is_a? Element 50 element 51 end 52 53 private 54 55 def bubble_up(index) 56 parent_index = index / 2 57 return if index <= 1 58 return if @elements[parent_index] <= @elements[index] 59 exchange(index, parent_index) 60 bubble_up(parent_index) 61 end 62 63 def bubble_down(index) 64 child_index = index * 2 65 max_index = @elements.size - 1 66 return if child_index > max_index 67 not_last_element = child_index < max_index 68 left_element = @elements[child_index] 69 right_element = @elements[child_index + 1] 70 child_index += 1 if not_last_element && right_element < left_element 71 return if @elements[index] <= @elements[child_index] 72 exchange(index, child_index) 73 bubble_down(child_index) 74 end 75 76 def exchange(source, target) 77 @elements[source], @elements[target] = @elements[target], @elements[source] 78 end 79end