Files
2025-12-02 20:37:18 +07:00

321 lines
6.4 KiB
Lua

MinHeapNode = HL.Class('MinHeapNode')
MinHeapNode.key = HL.Field(HL.Any)
MinHeapNode.value = HL.Field(HL.Number) << -1
MinHeapNode.index = HL.Field(HL.Number) << -1
MinHeapNode.Init = HL.Method(HL.Any, HL.Number, HL.Number) << function(self, key, value, index)
self.key = key
self.value = value
self.index = index
end
MinHeapNode.Clear = HL.Method() << function(self)
self.key = nil
self.value = -1
self.index = -1
end
HL.Commit(MinHeapNode)
MinHeap = HL.Class('MinHeap')
MinHeap.m_nodeList = HL.Field(HL.Table)
MinHeap.m_nodeMap = HL.Field(HL.Table)
MinHeap.m_count = HL.Field(HL.Number) << 0
MinHeap.m_nodeCache = HL.Field(HL.Forward("Stack"))
MinHeap.MinHeap = HL.Constructor() << function(self)
self.m_nodeList = {}
self.m_nodeMap = {}
self.m_nodeCache = require_ex("Common/Utils/DataStructure/Stack")()
end
MinHeap._Swap = HL.Method(HL.Number, HL.Number) << function(self, index1, index2)
if index1 == index2 then
return
end
local tmp = self.m_nodeList[index1]
self.m_nodeList[index1] = self.m_nodeList[index2]
self.m_nodeList[index1].index = index1
self.m_nodeMap[self.m_nodeList[index1].key] = self.m_nodeList[index1]
self.m_nodeList[index2] = tmp
self.m_nodeList[index2].index = index2
self.m_nodeMap[self.m_nodeList[index2].key] = self.m_nodeList[index2]
end
MinHeap._AdjustUp = HL.Method(HL.Number) << function(self, index)
local parent = math.floor(index / 2)
if parent == 0 then
return
end
if self.m_nodeList[index].value < self.m_nodeList[parent].value then
self:_Swap(index, parent)
self:_AdjustUp(parent)
end
end
MinHeap._AdjustDown = HL.Method(HL.Number) << function(self, index)
local size = self:Size()
local minIndex = index
if index * 2 <= size and self.m_nodeList[minIndex].value > self.m_nodeList[index * 2].value then
minIndex = index * 2
end
if index * 2 + 1 <= size and self.m_nodeList[minIndex].value > self.m_nodeList[index * 2 + 1].value then
minIndex = index * 2 + 1
end
if index ~= minIndex then
self:_Swap(index, minIndex)
self:_AdjustDown(minIndex)
end
end
MinHeap.Size = HL.Method().Return(HL.Number) << function(self)
return self.m_count
end
MinHeap.Add = HL.Method(HL.Any, HL.Number) << function(self, key, value)
if self.m_nodeMap[key] then
logger.error("MinHeap:Add same key", key, value)
return
end
local index = self:Size() + 1
local minHeapNode = self:_GetNode()
minHeapNode:Init(key, value, index)
minHeapNode.index = index
self.m_nodeList[index] = minHeapNode
self.m_nodeMap[minHeapNode.key] = minHeapNode
self.m_count = self.m_count + 1
self:_AdjustUp(self:Size())
end
MinHeap.Remove = HL.Method(HL.Any) << function(self, key)
local node = self.m_nodeMap[key]
if node then
local removeIndex = node.index
local size = self:Size()
local oldValue = node.value
self:_Swap(removeIndex, size)
self.m_nodeMap[key] = nil
self.m_nodeList[size] = nil
self.m_count = self.m_count - 1
self:_CacheNode(node)
if size ~= removeIndex then
if oldValue < self.m_nodeList[removeIndex].value then
self:_AdjustDown(removeIndex)
elseif oldValue > self.m_nodeList[removeIndex].value then
self:_AdjustUp(removeIndex)
end
end
end
end
MinHeap.UpdateValue = HL.Method(HL.Any, HL.Number) << function(self, key, newValue)
if not self.m_nodeMap[key] then
logger.error("MinHeap:UpdateValue obj not exist " .. tostring(key))
return
end
local node = self.m_nodeMap[key]
local oldValue = node.value
node.value = newValue
if newValue > oldValue then
self:_AdjustDown(node.index)
elseif newValue < oldValue then
self:_AdjustUp(node.index)
end
end
MinHeap.Min = HL.Method().Return(HL.Opt(HL.Any, HL.Number)) << function(self)
if self:Size() > 0 then
return self.m_nodeList[1].key, self.m_nodeList[1].value
end
return nil
end
MinHeap.Pop = HL.Method().Return(HL.Opt(HL.Any, HL.Number)) << function(self)
local size = self:Size()
if size > 0 then
local minKey = self.m_nodeList[1].key
local minValue = self.m_nodeList[1].value
if size > 1 then
self:_Swap(1, size)
local node = self.m_nodeList[size]
self.m_nodeMap[node.key] = nil
self.m_nodeList[size] = nil
self.m_count = self.m_count - 1
self:_CacheNode(node)
self:_AdjustDown(1)
else
local node = self.m_nodeList[size]
self.m_nodeMap[node.key] = nil
self.m_nodeList[size] = nil
self.m_count = self.m_count - 1
self:_CacheNode(node)
end
return minKey, minValue
end
logger.error("MinHeap:Pop empty")
return nil
end
MinHeap.Peek = HL.Method().Return(HL.Opt(HL.Any, HL.Number)) << function(self)
local size = self:Size()
if size > 0 then
local min = self.m_nodeList[1]
return min.key, min.value
end
logger.error("MinHeap:Pop empty")
return nil
end
MinHeap.GetValue = HL.Method(HL.Any).Return(HL.Opt(HL.Any)) << function(self, key)
return self.m_nodeMap[key] and self.m_nodeMap[key].value or nil
end
MinHeap.Find = HL.Method(HL.Any).Return(HL.Boolean) << function(self, key)
return self.m_nodeMap[key] and true or false
end
MinHeap.NodeIter = HL.Method().Return(HL.Any) << function(self)
local i = 0
local keys = {}
for k, _ in pairs(self.m_nodeMap) do
table.insert(keys, k)
end
return function()
i = i + 1
if self.m_nodeMap[keys[i]] then
return self.m_nodeMap[keys[i]]
end
end
end
MinHeap.Clear = HL.Method() << function(self)
for _, node in pairs(self.m_nodeMap) do
self:_CacheNode(node)
end
self.m_nodeList = {}
self.m_nodeMap = {}
self.m_count = 0
end
MinHeap._GetNode = HL.Method().Return(MinHeapNode) << function(self)
if self.m_nodeCache:Empty() then
return MinHeapNode()
else
return self.m_nodeCache:Pop()
end
end
MinHeap._CacheNode = HL.Method(MinHeapNode) << function(self, node)
node:Clear()
self.m_nodeCache:Push(node)
end
HL.Commit(MinHeap)
return MinHeap