LRUCache

# LRU: Least recently used,最近最少使用

 

【一般使用链表+map这两个数据结构来实现】

# 使用map来加快缓存数据的查找

# 使用链表来记录最近的访问情况,最近被访问了(Get和Put都属于是最近访问了),就会被移到链表头

# 当Put进去的数据超过缓存容量时,链表尾部的元素就会被移出缓存

 

local LRUCache = {}
LRUCache.__index = LRUCache

function LRUCache.new(capacity)
    local obj = {}
    setmetatable(obj, LRUCache)
    obj:ctor(capacity)
    return obj
end

function LRUCache:ctor(capacity)
    self.capacity = capacity
    self.cache = {}
    self.list = LinkedList.new()
end

function LRUCache:Put(key, value)
    local node = self.cache[key]
    if nil == node then --缓存中没有
        node = self.list:AddFirst({k=key, v=value})
        self.cache[key] = node
        --如果超过了容量, 移除链表尾部元素
        if self.list:GetCount() > self.capacity then
            local nodeValue = self.list:RemoveLast():GetValue()
            self.cache[nodeValue.k] = nil
            --print(">capacity", nodeValue.k, nodeValue.v)
        end
    else --缓存中已经有了
        node:GetValue().v = value
        --最近被访问了, 放到链表最前面
        self.list:MoveToFirst(node)
    end
end

function LRUCache:Get(key)
    local node = self.cache[key]
    if nil == node then return nil end --缓存中没有
    self.list:MoveToFirst(node)
    return node:GetValue().v
end

function LRUCache:Remove(key)
    local node = self.cache[key]
    if nil == node then return end --缓存中没有
    self.cache[key] = nil
    self.list:MoveToFirst(node)
end

function LRUCache:Clear()
    self.cache = {}
    self.list:Clear()
end

 

【链表部分】

local Node = {}
Node.__index = Node

function Node.new(list, value)
    local obj = {}
    setmetatable(obj, Node)
    obj:ctor(list, value)
    return obj
end

function Node:ctor(list, value)
    self.list = list
    self.value = value
    self.next = nil
    self.prev = nil
end

function Node:SetValue(value)
    self.value = value
end
function Node:GetValue()
    return self.value
end

function Node:GetNext()
    return self.next
end
function Node:GetPrev()
    return self.prev
end

 

local LinkedList = {}
LinkedList.__index = LinkedList

function LinkedList.new()
    local obj = {}
    setmetatable(obj, LinkedList)
    obj:ctor()
    return obj
end

function LinkedList:ctor()
    self.head = nil
    self.tail = nil
    self.count = 0
end

function LinkedList:GetCount()
    return self.count
end

function LinkedList:Clear()
    if 0 == self.count then return end

    local allNodes = {}
    local node = self.head
    while nil ~= node do
        node.list = nil
        node.prev = nil
        local tempNext = node.next
        node.next = nil
        table.insert(allNodes, node)
        node = tempNext
    end
    self.head = nil
    self.tail = nil
    self.count = 0
    return allNodes --所有游离状nodes
end

function LinkedList:GetFirst()
    if 0 == self.count then return nil end
    return self.head
end
function LinkedList:GetFirstValue()
    if 0 == self.count then return nil end
    return self.head:GetValue()
end

function LinkedList:GetLast()
    if 0 == self.count then return nil end
    return self.tail
end
function LinkedList:GetLastValue()
    if 0 == self.count then return nil end
    return self.tail:GetValue()
end

function LinkedList:AddFirst(value)
    if 0 == self.count then
        self.count = 1
        self.head = Node.new(self, value)
        self.tail = self.head
        return self.head
    end
    self.count = self.count + 1
    local newHead = Node.new(self, value)
    newHead.next = self.head
    self.head.prev = newHead
    self.head = newHead
    return newHead
end

function LinkedList:AddLast(value)
    if 0 == self.count then
        self.count = 1
        self.head = Node.new(self, value)
        self.tail = self.head
        return self.head
    end
    self.count = self.count + 1
    local newTail = Node.new(self, value)
    newTail.prev = self.tail
    self.tail.next = newTail
    self.tail = newTail
    return newTail
end

---移动到链表头
function LinkedList:MoveToFirst(node)
    if node.list ~= self then return end
    if self.head == node then return end
    --断开原来的位置
    if self.tail == node then
        local newTail = node.prev
        newTail.next = nil --断开旧tail
        node.prev = nil --旧tail清除prev
        self.tail = newTail --设置新tail
    else
        node.prev.next = node.next
        node.next.prev = node.prev
        node.prev = nil
    end

    --变成新的head
    node.next = self.head
    self.head.prev = node
    self.head = node
end

function LinkedList:RemoveFirst()
    if 0 == self.count then return nil end

    local ret = self.head
    if 1 == self.count then
        self.head = nil
        self.tail = nil
        self.count = 0
    else
        local newHead = self.head.next
        newHead.prev = nil --断开旧head
        self.head.next = nil--旧head清除next
        self.head = newHead --设置新head
        self.count = self.count - 1
    end
    ret.list = nil
    return ret
end

---移除链表尾
function LinkedList:RemoveLast()
    if 0 == self.count then return nil end

    local ret = self.tail
    if 1 == self.count then
        self.head = nil
        self.tail = nil
        self.count = 0
    else
        local newTail = self.tail.prev
        newTail.next = nil --断开旧tail
        self.tail.prev = nil --旧tail清除prev
        self.tail = newTail --设置新tail
        self.count = self.count - 1
    end
    ret.list = nil
    return ret
end

function LinkedList:Remove(node)
    if node.list ~= self then return end
    if self.head == node then
        self:RemoveFirst()
    elseif self.tail == node then
        self:RemoveLast()
    else
        node.prev.next = node.next
        node.next.prev = node.prev
        node.prev = nil
        node.next = nil
        node.list = nil
    end
end

function LinkedList:__tostring()
    if 0 == self.count then return "" end

    local strTb = {}
    local node = self.head
    while nil ~= node do
        if nil == node.value then
            table.insert(strTb, "nil")
        else
            table.insert(strTb, tostring(node.value))
        end
        node = node.next
    end
    return table.concat(strTb, ",")
end

 

【参考】

LRU算法 - Yrion - 博客园 (cnblogs.com)

 

原文地址:https://www.cnblogs.com/sailJs/p/16024264.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍“基于nodejs的ssh2怎么实现自动化部署”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“基于nodejs...
本文小编为大家详细介绍“nodejs怎么实现目录不存在自动创建”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs怎么实现目录不存在自动创建”文章能帮助大...
这篇“如何把nodejs数据传到前端”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这...
本文小编为大家详细介绍“nodejs如何实现定时删除文件”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs如何实现定时删除文件”文章能帮助大家解决疑惑...
这篇文章主要讲解了“nodejs安装模块卡住不动怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来...
今天小编给大家分享一下如何检测nodejs有没有安装成功的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文...
本篇内容主要讲解“怎么安装Node.js的旧版本”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎...
这篇“node中的Express框架怎么安装使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要介绍“nodejs如何实现搜索引擎”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“nodejs如何实现搜索引擎...
这篇文章主要介绍“nodejs中间层如何设置”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“nodejs中间层如何设置”文...
这篇文章主要介绍“nodejs多线程怎么实现”,在日常操作中,相信很多人在nodejs多线程怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
这篇文章主要讲解了“nodejs怎么分布式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“nodejs怎么分布式”...
本篇内容介绍了“nodejs字符串怎么转换为数组”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情...
这篇文章主要介绍了nodejs如何运行在php服务器的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇nodejs如何运行在php服务器文章都...
本篇内容主要讲解“nodejs单线程如何处理事件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“nodejs单线程如何...
这篇文章主要介绍“nodejs怎么安装ws模块”,在日常操作中,相信很多人在nodejs怎么安装ws模块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
本篇内容介绍了“怎么打包nodejs代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!
本文小编为大家详细介绍“nodejs接收到的汉字乱码怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs接收到的汉字乱码怎么解决”文章能帮助大家解...
这篇“nodejs怎么同步删除文件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇...
今天小编给大家分享一下nodejs怎么设置淘宝镜像的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希