内存淘汰机制——LRU与LFU
内存淘汰机制之LRU与LFU
- LRU(Least Recently Used):淘汰 近期最不会访问的数据
- LFU(Least Frequently Used):淘汰 最不经常使用(访问次数少)
所谓淘汰就是将内存中指定部分的数据移除,释放空间提供给新来的数据。
LRU
LeetCode入口👉👉👉No.146

- 
存数据,将数据插入链表头部;如果内存满了,需要先将链表尾部数据删除,再插入 
- 
取数据,每次将取到的数据重新放到链表头部 
LRU一般使用哈希链表(哈希表+双向链表)实现,可以在 \(O(1)\) 复杂度内实现插入、删除。
OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素;popitem(last=False) 删除并返回第一个被添加进去的元素
coding:
#--python
#使用python自带哈希链表(有序字典OrderedDict)实现
from collections import OrderedDict
class LRUCache(OrderedDict):
    def __init__(self, capacity: int):
        self.capacity = capacity
    def get(self, key: int) -> int:
        if key not in self:
            return -1
        self.move_to_end(key)
        return self[key]
    def put(self, key: int, value: int) -> None:
        if key in self:
            self.move_to_end(key)
        self[key] = value	#更新value
        if len(self) > self.capacity:
            self.popitem(last=False)
自己实现哈希链表

#--python
#定义双向链表节点
class DLinkNode():
    def __init__(self,key=0,value=0):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None
class LRUCache():
    def __init__(self,capacity):
        self.cache = {}
        self.size = 0
        self.capacity = capacity
        #定义伪头部 伪尾部节点
        self.head,self.tail = DLinkNode(),DLinkNode()
        self.head.next = self.tail
        self.tail.prev = self.head
    
    #模拟OrderedDict 定义 添加 删除 移动头部方法
    def _add_node(self,node):
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev = node
        self.head.next = node
    
    def _remove_node(self,node):
        node.next.prev = node.prev
        node.prev.next = node.next
    
    def _move_to_head(self,node):
        self._remove_node(node)
        self._add_node(node)
    def _pop_tail(self):
        node = self.tail.prev
        self._remove_node(node)
        return node
    def get(self,key):
        if key not in self.cache:
            return -1
        node = self.cache[key]
        self._move_to_head(node)
        return node.value
    
    def put(self,key,value):
        #如果key不存在,创建node 添加
        if key not in self.cache:
            node = DLinkNode(key,value)
            self.cache[key] = node
            self._add_node(node)
            self.size += 1
            #如果满了,删除双向链表节点 和 字典对应键
            if self.size > self.capacity:
                node = self._pop_tail()
                self.cache.pop(node.key)
                self.size -= 1
        else:
            node = self.cache[key]
            node.value = value
            self._move_to_head(node)
LFU
LeetCode入口👉👉👉No.460

- 维护一个访问频次的数据结构,取数据,访问频次加一,根据访问次数排序
- 存数据,当缓存满时,淘汰点访问次数最小的
使用双哈希表 keyMap 和 freqMap
coding:
#--python
#双哈希表 
class Node:
    def __init__(self, key, val, pre=None, nex=None, freq=0):
        self.pre = pre
        self.nex = nex
        self.freq = freq
        self.val = val
        self.key = key
        
    def insert(self, nex):
        nex.pre = self
        nex.nex = self.nex
        self.nex.pre = nex
        self.nex = nex
    
def create_linked_list():
    head = Node(0, 0)
    tail = Node(0, 0)
    head.nex = tail
    tail.pre = head
    return (head, tail)
class LFUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.size = 0
        self.minFreq = 0
        self.freqMap = collections.defaultdict(create_linked_list)
        self.keyMap = {}
    def delete(self, node):
        if node.pre:
            node.pre.nex = node.nex
            node.nex.pre = node.pre
            if node.pre is self.freqMap[node.freq][0] and node.nex is self.freqMap[node.freq][-1]:
                self.freqMap.pop(node.freq)
        return node.key
        
    def increase(self, node):
        node.freq += 1
        self.delete(node)
        self.freqMap[node.freq][-1].pre.insert(node)
        if node.freq == 1:
            self.minFreq = 1
        elif self.minFreq == node.freq - 1:
            head, tail = self.freqMap[node.freq - 1]
            if head.nex is tail:
                self.minFreq = node.freq
    def get(self, key: int) -> int:
        if key in self.keyMap:
            self.increase(self.keyMap[key])
            return self.keyMap[key].val
        return -1
    def put(self, key: int, value: int) -> None:
        if self.capacity != 0:
            if key in self.keyMap:
                node = self.keyMap[key]
                node.val = value
            else:
                node = Node(key, value)
                self.keyMap[key] = node
                self.size += 1
            if self.size > self.capacity:
                self.size -= 1
                deleted = self.delete(self.freqMap[self.minFreq][0].nex)
                self.keyMap.pop(deleted)
            self.increase(node)
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号