1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/utils/priority_queue.lua

123 lines
3.1 KiB
Lua
Raw Normal View History

2019-06-22 23:36:04 +02:00
local floor = math.floor
local getmetatable = getmetatable
local setmetatable = setmetatable
2019-06-22 23:36:04 +02:00
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.
2019-06-23 11:07:17 +02:00
-- @param comparator <function|nil> the comparator function used to compare elements, if nil the
-- deafult comparator is used.
2019-06-22 23:36:04 +02:00
-- @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
end
local mt = {comparator = comparator}
return setmetatable({}, mt)
end
function PriorityQueue.load(self, comparator)
if comparator == nil then
comparator = default_comparator
end
local mt = {comparator = comparator}
return setmetatable(self or {}, mt)
end
local function get_comparator(self)
local mt = getmetatable(self)
return mt.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 = get_comparator(self)
2019-06-22 23:36:04 +02:00
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 = get_comparator(self)
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.
2019-06-23 11:07:17 +02:00
-- If the priority queue is empty returns nil.
2019-06-22 23:36:04 +02:00
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.
2019-06-23 11:07:17 +02:00
-- If the priority queue is empty returns nil.
2019-06-22 23:36:04 +02:00
function PriorityQueue.peek(self)
return self[1]
2018-01-31 22:29:15 +02:00
end
return PriorityQueue