算法:矿点间行走-Use最小堆+带权最短路径

最小堆

function MinHeap:Ctor(tData)
    self.tArray = tData or {}  
    if #self.tArray > 1 then
        self:adjust()
    end    
end

function MinHeap:GetSize()
    return #self.tArray
end

-- 调整
function MinHeap:adjust()
    local nLastParentIndex = math.floor((#self.tArray - 2) / 2 + 1)
    for nParentIndex = nLastParentIndex, 1, -1 do
        self:siftdown(nParentIndex)
    end
end

-- 下沉
function MinHeap:siftdown(nParentIndex)  
    local nChildLeftIndex = nParentIndex * 2
    if not self.tArray[nChildLeftIndex] then    -- 没有左子节点
        return
    end
    
    local nChildLeftValue = self.tArray[nChildLeftIndex]
    if self.tArray[nChildLeftIndex].nValue then
        nChildLeftValue = self.tArray[nChildLeftIndex].nValue
    end    
    
    local nChildRightIndex = nParentIndex * 2 + 1
    local nChildRightValue = self.tArray[nChildRightIndex]
    if self.tArray[nChildRightIndex] and self.tArray[nChildRightIndex].nValue then
        nChildRightValue = self.tArray[nChildRightIndex].nValue
    end   
    local nParentValue = self.tArray[nParentIndex]
    if self.tArray[nParentIndex].nValue then
        nParentValue = self.tArray[nParentIndex].nValue
    end  
    local nChildIndex

    if nChildLeftValue then
        nChildIndex = nChildLeftIndex 
    end
    if nChildRightValue and nChildRightValue < nChildLeftValue then
        nChildIndex = nChildRightIndex
    end  
    local nChildValue = self.tArray[nChildIndex]
    if self.tArray[nChildIndex].nValue then
        nChildValue = self.tArray[nChildIndex].nValue
    end  

    if nChildValue < nParentValue then
        local parent = self.tArray[nParentIndex]
        self.tArray[nParentIndex] = self.tArray[nChildIndex]
        self.tArray[nChildIndex] = parent
        self:siftdown(nChildIndex)
    end    
end

-- 上浮 
function MinHeap:siftup(nChildIndex)
    if nChildIndex == 1 then -- 根节点
        return
    end    
    local nChildValue = self.tArray[nChildIndex]
    if self.tArray[nChildIndex].nValue then
        nChildValue = self.tArray[nChildIndex].nValue
    end    
    local nParentIndex = math.floor(nChildIndex / 2)
    local nParentValue = self.tArray[nParentIndex]
    if self.tArray[nParentIndex].nValue then
        nParentValue = self.tArray[nParentIndex].nValue
    end    
    if nChildValue < nParentValue then
        local parent = self.tArray[nParentIndex]
        self.tArray[nParentIndex] = self.tArray[nChildIndex]
        self.tArray[nChildIndex] = parent
        self:siftup(nParentIndex)
    end    
end

-- 插入
function MinHeap:Insert(value)
    table.insert(self.tArray, value)
    self:siftup(#self.tArray)
end

-- 获取根节点
function MinHeap:GetMin()
    if self:GetSize() < 1 then
        return nil
    end 
    local rootValue = self.tArray[1]
   
    self.tArray[1] = self.tArray[#self.tArray]
    self:siftdown(1)
    self.tArray[#self.tArray] = nil
    return rootValue
end

return MinHeap

带权最短路径

function Graph:Ctor(tLinks)
    self.tLinks = tLinks or {}
end

-- 最短路径算法Dijkstra
function Graph:GetShortestPaths(nSrc, nDest, tBanDest)
    -- lua_trace("nSrc %d, nDest %d", nSrc, nDest)
    if nSrc == nDest then
        return {}
    end  
    
    tBanDest = tBanDest or {}  
    if tBanDest[nDest] then
        return {}
    end    

    local tDefaultValue = {}
    table.insert(tDefaultValue, {nIndex = nSrc, nValue = 0})

    -- 起点到其他点的邻接表
    -- self.tAdjacencyList[nSrc] = {}
    local tAdjacencyList = {}

    local oMinHeap = MinHeap:new(tDefaultValue)

    local bConnectDest = false
    -- 循环遍历直到找到到达目标的最小值
    while(true) do
        local bSmallerNode = false
        local minValue = oMinHeap:GetMin()
        local nIndex = minValue.nIndex
        local nValue = minValue.nValue  -- 起点到这个点的权值
        local tLink = self.tLinks[nIndex] 
        if not tLink then
            lua_trace("nIndex %d", nIndex)
            lua_trace("tLink"..tLink)
        end    
        -- 遍历邻接点,计算起点到他们的权值
        for nNeighborIndex, nEdgeValue in pairs(tLink) do
            local nNewValue = nValue + nEdgeValue
            -- if not self.tAdjacencyList[nSrc][nNeighborIndex] or self.tAdjacencyList[nSrc][nNeighborIndex].nValue > nNewValue then
            if nNeighborIndex ~= nSrc and not tBanDest[nNeighborIndex] and
            (not tAdjacencyList[nNeighborIndex] or tAdjacencyList[nNeighborIndex].nValue > nNewValue) then
                -- 更新起点到该点的前置节点和权值
                local tNewValue =  {nIndex = nNeighborIndex, nPreIndex = nIndex, nValue = nNewValue}
                tAdjacencyList[nNeighborIndex] =  tNewValue
                oMinHeap:Insert(tNewValue)

                bSmallerNode = true
                if nNeighborIndex == nDest then
                    bConnectDest = true
                end    
            end    
        end   
        
        -- 已经没有更短的路径
        if oMinHeap:GetSize() == 0 or (bConnectDest and not bSmallerNode) then
            break
        end    
    end

    -- 没有找到路径
    if not bConnectDest then
        return nil
    end    

    -- 回溯最短路径
     --{nSrc, ..., ..., nDest}
    local tShortestPaths = {}
    -- local tShortestPaths_Reverse = {}

    local nCurIndex = nDest
    table.insert(tShortestPaths, 1, nCurIndex)
    -- table.insert(tShortestPaths_Reverse, nCurIndex)
 
    while(true) do

        nCurIndex = tAdjacencyList[nCurIndex].nPreIndex
        if nCurIndex == nSrc then
            table.insert(tShortestPaths, 1, nSrc)
            -- table.insert(tShortestPaths_Reverse, nSrc)
            break
        end    
        local tValue = tAdjacencyList[nCurIndex]   
        table.insert(tShortestPaths, 1, tValue.nIndex)
        -- table.insert(tShortestPaths_Reverse, tValue.nIndex)
    end

    return tAdjacencyList[nDest].nValue, tShortestPaths

end

function Graph:GetAllShortestPaths(tBanDest)
    local tAllShortestPaths = {}
    for nSrc, _ in pairs(self.tLinks) do 
        tAllShortestPaths[nSrc] = tAllShortestPaths[nSrc] or {}       
        for nDest, _ in pairs(self.tLinks) do
            if nSrc ~= nDest and not tAllShortestPaths[nSrc][nDest] then          
                tAllShortestPaths[nDest] = tAllShortestPaths[nDest] or {}

                local nValue, tShortestPaths = self:GetShortestPaths(nSrc, nDest, tBanDest)
                tAllShortestPaths[nSrc][nDest] = {tPath = tShortestPaths, nValue = nValue}
            end    
        end    
    end    
    return tAllShortestPaths
end

 

posted @ 2022-06-06 19:30  银龙背上的骑士  阅读(27)  评论(0编辑  收藏  举报