内存淘汰机制之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)

内存淘汰机制——LRU与LFU的更多相关文章

  1. 4.redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?

    作者:中华石杉 面试题 redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 面试官心理分析 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当 ...

  2. redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?

    redis的过期策略都有哪些? 设置过期时间: set key 的时候,使用expire time,就是过期时间.指定这个key比如说只能存活一个小时?10分钟?指定缓存到期就会失效. redis的过 ...

  3. Redis 内存淘汰机制详解

    一般来说,缓存的容量是小于数据总量的,所以,当缓存数据越来越多,Redis 不可避免的会被写满,这时候就涉及到 Redis 的内存淘汰机制了.我们需要选定某种策略将"不重要"的数据 ...

  4. Redis 中的过期删除策略和内存淘汰机制

    Redis 中 key 的过期删除策略 前言 Redis 中 key 的过期删除策略 1.定时删除 2.惰性删除 3.定期删除 Redis 中过期删除策略 从库是否会脏读主库创建的过期键 内存淘汰机制 ...

  5. redis 的过期策略都有哪些?内存淘汰机制都有哪些?

    面试题 redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 面试官心理分析 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当然的认为写进 r ...

  6. Redis系列--内存淘汰机制(含单机版内存优化建议)

    https://blog.csdn.net/Jack__Frost/article/details/72478400?locationNum=13&fps=1 每台redis的服务器的内存都是 ...

  7. Redis内存淘汰机制

    转自:https://my.oschina.net/andylucc/blog/741965 摘要 Redis是一款优秀的.开源的内存数据库,我在阅读Redis源码实现的过程中,时时刻刻能感受到Red ...

  8. redis过期策略和内存淘汰机制

    目录 常见的删除策略 redis使用的过期策略:定期删除+惰性删除 定期删除 惰性删除 为什么要采用定期删除+惰性删除2种策略呢? redis内存淘汰机制 常见的删除策略 1.定时删除:在设置键的过期 ...

  9. Redis(六)--- Redis过期策略与内存淘汰机制

    1.简述 关于Redis键的过期策略,首先要了解两种时间的区别,生存时间和过期时间: 生存时间:一段时长,如30秒.6000毫秒,设置键的生存时间就是设置这个键可以存在多长时间,命令有两个 expir ...

随机推荐

  1. 让 .NET 轻松构建中间件模式代码(二)

    让 .NET 轻松构建中间件模式代码(二)--- 支持管道的中断和分支 Intro 上次实现了一个基本的构建中间件模式的中间件构建器,现在来丰富一下功能,让它支持中断和分支,分别对应 asp.net ...

  2. Ceph学习笔记(4)- OSD

    前言 OSD是一个抽象的概念,对应一个本地块设备(一块盘或一个raid组) 传统NAS和SAN存储是赋予底层物理磁盘一些CPU.内存等,使其成为一个对象存储设备(OSD),可以独立进行磁盘空间分配.I ...

  3. hive常用函数三

    日期函数 1. UNIX时间戳转日期函数: from_unixtime 语法: from_unixtime(bigint unixtime[, string format]) 返回值: string ...

  4. Visual C++ 6.0踩坑记录---在Win10下安装Visual C++ 6.0安装成功后点击“打开”按钮闪退问题

    前言: 为了更好的学习C及C++,前段时间下载了Microsoft Visual C++ 6.0(以下简称VC6),原因是VC6具有查看反汇编代码.监视内存.寄存器等功能,并且因为本人正在学习滴水逆向 ...

  5. 10行代码,用python能做出什么骚操作

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:小栗子 PS:如有需要Python学习资料的小伙伴可以加点击下方链接自 ...

  6. 猜数字和飞机大战(Python零基础入门)

    前言 最近有很多零基础初学者问我,有没有适合零基础学习案例,毕竟零基础入门的知识点是非常的枯燥乏味的,如果没有实现效果展示出来,感觉学习起来特别的累,今天就给大家介绍两个零基础入门的基础案例:猜数字游 ...

  7. F - Distinct Numbers

    链接:https://atcoder.jp/contests/abc143/tasks/abc143_f 题解:开两个数组,其中一个arr用来保存每个元素出现的次数,同时再开一个数组crr用来保存出现 ...

  8. gdb 调试中No symbol “***” in current context解决方法

    主要是因为GCC/G++版本和GDB不匹配造成的,网上也有说是因为O2优化问题,具体啥原因需要自己尝试一下. 解决: 放狗搜索,解决办法是在编译是加-gdwarf-3即可,出现这样的原因是gcc,gd ...

  9. GIT生成ssh(window7系统)——git工具篇

    由于本地git仓库和github仓库直接的传递需要ssh加密的,所以必须要生成ssh,下面是具体的操作步骤: 1.打开GIT命令行,输入命令:ssh-keygen -t rsa -C "yo ...

  10. 有关HTTP协议

    有关HTTP协议:https://www.cnblogs.com/an-wen/p/11180076.html