概述
LRU是Least Recently Used
的缩写,译为最近最少使用。它的理论基础为 “最近使用的数据会在未来一段时期内仍然被使用,已经很久没有使用的数据大概率在未来很长一段时间仍然不会被使用” 由于该思想非常契合业务场景 ,并且可以解决很多实际开发中的问题,所以我们经常通过LRU的思想来作缓存,一般也将其称为LRU缓存机制。
原理
实现LRU时,我们需要关注它的读性能和写性能,理想的LRU应该可以在O(1)
的时间内读取一条数据或更新一条数据,也就是说读写的时间复杂度都是O(1)
。
此时很容易想到使用哈希表,根据数据的键访问数据可以达到O(1)
的速度。但是更新缓存的速度却无法达到O(1),因为需要确定哪一条数据的访问时间最早,这需要遍历所有缓存才能找到。
因此,我们需要一种既按访问时间排序,又能在常数时间内随机访问的数据结构。
这可以通过哈希表+双向链表实现:
- 哈希表保证通过key访问数据的时间为O(1).
- 双向链表则按照访问时间的顺序依次穿过每个数据。
之所以选择双向链表而不是单链表,是为了可以从中间任意结点修改链表结构,而不必从头结点开始遍历。
图解示例
假如我们设计一个容量大小为4的LRU缓存。
1.先添加4个元素
上排是哈希表的 key, 我们依次添加:k1, k2, k3, k4
。 下排是哈希表的 node 结构体,里面包括(key, value) pair
,我们用双向链表连接。分别为n1, n2, n3, n4
。
最新添加的在链表头部,表示最近使用。
当我们添加第四个元素的时候如图所示:
2.添加k5
把k5放在哈希表中,然后把n5放在链表头部,此时由于hash表的size大于容量4,我们需要删除一个元素,从尾部删除,尾部代表最久没使用。
同时从哈希表中删除尾部n1对应的k1。