2019-06-22 23:36:04 +02:00
|
|
|
local Debug = require 'utils.debug'
|
|
|
|
local is_closure = Debug.is_closure
|
|
|
|
local floor = math.floor
|
|
|
|
|
2018-01-31 22:29:15 +02:00
|
|
|
local PriorityQueue = {}
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
local function default_comparator(a, b)
|
|
|
|
return a < b
|
2018-01-31 22:29:15 +02:00
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
--- Min heap implementation of a priority queue. Smaller elements, as determined by the comparator,
|
|
|
|
-- have a higher priority.
|
|
|
|
-- @param comparator <function|nil> the comparator function used to compare elements
|
|
|
|
-- @usage
|
|
|
|
-- local PriorityQueue = require 'utils.priority_queue'
|
|
|
|
--
|
|
|
|
-- local queue = PriorityQueue.new()
|
|
|
|
-- PriorityQueue.push(queue, 4)
|
|
|
|
-- PriorityQueue.push(queue, 7)
|
|
|
|
-- PriorityQueue.push(queue, 2)
|
|
|
|
--
|
|
|
|
-- game.print(PriorityQueue.pop(queue)) -- 2
|
|
|
|
-- game.print(PriorityQueue.pop(queue)) -- 4
|
|
|
|
-- game.print(PriorityQueue.pop(queue)) -- 7
|
|
|
|
function PriorityQueue.new(comparator)
|
|
|
|
if comparator == nil then
|
|
|
|
comparator = default_comparator
|
|
|
|
elseif is_closure(comparator) then
|
|
|
|
error('comparator cannot be a closure.', 2)
|
|
|
|
end
|
|
|
|
|
|
|
|
return {_comparator = comparator}
|
2018-01-31 22:29:15 +02:00
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
local function heapify_from_end_to_start(self)
|
|
|
|
local comparator = self._comparator
|
|
|
|
local pos = #self
|
2018-01-31 22:29:15 +02:00
|
|
|
while pos > 1 do
|
2019-06-22 23:53:58 +02:00
|
|
|
local parent = floor(pos * 0.5)
|
2019-06-22 23:36:04 +02:00
|
|
|
local a, b = self[pos], self[parent]
|
|
|
|
if comparator(a, b) then
|
|
|
|
self[pos], self[parent] = b, a
|
2018-01-31 22:29:15 +02:00
|
|
|
pos = parent
|
|
|
|
else
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
local function heapify_from_start_to_end(self)
|
|
|
|
local comparator = self._comparator
|
2018-01-31 22:29:15 +02:00
|
|
|
local parent = 1
|
|
|
|
local smallest = 1
|
2019-06-22 23:36:04 +02:00
|
|
|
local count = #self
|
2018-01-31 22:29:15 +02:00
|
|
|
while true do
|
|
|
|
local child = parent * 2
|
2019-06-22 23:36:04 +02:00
|
|
|
if child > count then
|
2018-01-31 22:29:15 +02:00
|
|
|
break
|
|
|
|
end
|
2019-06-22 23:36:04 +02:00
|
|
|
if comparator(self[child], self[parent]) then
|
2018-01-31 22:29:15 +02:00
|
|
|
smallest = child
|
|
|
|
end
|
|
|
|
child = child + 1
|
2019-06-22 23:36:04 +02:00
|
|
|
if child <= count and comparator(self[child], self[smallest]) then
|
2018-01-31 22:29:15 +02:00
|
|
|
smallest = child
|
|
|
|
end
|
|
|
|
|
|
|
|
if parent ~= smallest then
|
2019-06-22 23:36:04 +02:00
|
|
|
self[parent], self[smallest] = self[smallest], self[parent]
|
2018-01-31 22:29:15 +02:00
|
|
|
parent = smallest
|
|
|
|
else
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
--- Returns the number of the number of elements in the priority queue.
|
|
|
|
function PriorityQueue.size(self)
|
|
|
|
return #self
|
2018-01-31 22:29:15 +02:00
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
-- Inserts an element into the priority queue.
|
|
|
|
function PriorityQueue.push(self, element)
|
|
|
|
self[#self + 1] = element
|
|
|
|
heapify_from_end_to_start(self)
|
2018-01-31 22:29:15 +02:00
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
-- Removes and returns the highest priority element from the priority queue.
|
|
|
|
function PriorityQueue.pop(self)
|
|
|
|
local element = self[1]
|
2018-01-31 22:29:15 +02:00
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
self[1] = self[#self]
|
|
|
|
self[#self] = nil
|
|
|
|
heapify_from_start_to_end(self)
|
2018-01-31 22:29:15 +02:00
|
|
|
|
|
|
|
return element
|
|
|
|
end
|
|
|
|
|
2019-06-22 23:36:04 +02:00
|
|
|
-- Returns, without removing, the highest priority element from the priority queue.
|
|
|
|
function PriorityQueue.peek(self)
|
|
|
|
return self[1]
|
2018-01-31 22:29:15 +02:00
|
|
|
end
|
|
|
|
|
2018-11-20 12:46:42 +02:00
|
|
|
return PriorityQueue
|