图解LFU与LRU:从浏览器缓存到操作系统的15个核心应用场景
在计算机科学领域,缓存淘汰算法如同数字世界的守门人,它们决定了哪些数据应该留下,哪些需要被请离。当缓存空间有限时,LFU(最不经常使用)和LRU(最近最少使用)这两位"门卫"会基于不同的策略做出决策。想象一下浏览器缓存就像一个繁忙的图书馆,LFU会优先保留被频繁借阅的书籍,而LRU则倾向于保留最近被借阅过的书目。
1. 算法原理深度解析
1.1 LRU:时间维度的智慧
LRU算法建立在一个直观的假设上:如果数据最近被访问过,那么它将来被再次访问的概率也更高。这种算法像一位严谨的图书管理员,总是把最新归还的书放在书架最显眼的位置。
核心操作流程:
- 新数据插入到链表头部
- 每当缓存命中(即数据被访问),将数据移到链表头部
- 当链表满时,丢弃链表尾部的数据
class LRUCache:
def __init__(self, capacity: int):
self.cache = OrderedDict()
self.capacity = capacity
def get(self, key: int) -> int:
if key not in self.cache:
return -1
self.cache.move_to_end(key)
return self.cache[key]
def put(self, key: int, value: int) -> None:
if key in self.cache:
self.cache.move_to_end(key)
self.cache[key] = value
if len(self.cache) > self.capacity:
self.cache.popitem(last=False)
1.2 LFU:频率统计的艺术
LFU则采用了不同的策略,它认为历史访问频率是预测未来使用模式的最佳指标。这就像图书馆统计每本书的借阅次数,保留那些最受欢迎的书籍。
LFU实现关键点:
- 为每个数据项维护访问计数器
- 使用频率哈希表快速定位相同频率的数据
- 需要双重链表结构维护访问顺序
class LFUCache {
// 频率哈希表:频率 -> 具有该频率的键集合
Map<Integer, LinkedHashSet<Integer>> freqMap;
// 键值存储
Map<Integer, Integer> keyToValue;
// 键到频率的映射
Map<Integer, Integer> keyToFreq;
int minFreq;
int capacity;
public int get(int key) {
if (!keyToValue.containsKey(key)) return -1;
increaseFreq(key);
return keyToValue.get(key);
}
private void increaseFreq(int key) {
int freq = keyToFreq.get(key);
keyToFreq.put(key, freq + 1);
freqMa


被折叠的 条评论
为什么被折叠?



