什么是LRU算法
LRU算法是一种缓存淘汰策略,也称为最近最久未使用算法。对于计算机来说,缓存的容量是有限的,当缓存满的时候 势必要淘汰掉无用或没那么有用的缓存,我们的LRU邀约而生。其思路就是淘汰掉最久没有使用到访问到的缓存。
思路
哪个数据是最久未使用的呢?
我们可以将每一个数据当成一个节点,每当我们访问它们的时候,就将这个节点提到节点的头部,这样后最后面的节点就是我们需要淘汰的最久未使用的数据。
图解
![](https://i-blog.csdnimg.cn/blog_migrate/e5cbc617b6b38114866d27f2a83d5693.png)
实现的数据结构
现在思路有了,让我们来说说为什么使用双链表+散列表的数据结构吧~
首先我们需要将每一个节点储存起来,势必需要一个集合来储存起来。(使用链表)
这就有了两种选择ArrayList和LinkedList这两种常见的集合。ArrayList集合底层使用的是数组实现,而LinkedList集合底层使用的是链表实现。
而我们每一次访问都需要将访问到的节点进行移动到第一个节点,后面的节点需要依次往下移动。我们的数组移动起来是非常耗时的,复杂度O(n),显然不划算,故选择链表,移动一个节点只需要将链表的指向改变,复杂度O(1)。所以我们将移动节点的性能提高到了O(1)。
事实上是链表也有一些小问题,我们都知道,链表的移动是O(1),但是链表的查询性能是O(n)呀。当我们需要访问某个节点的时候,我们需要遍历一遍链表才知道这个节点是否在我们的缓存之中,这显然不合适。(使用散列表)
我们可以添加一个散列表去提高我们的查询效率。最合适的就是我们最常用的HashMap~
我们的HashMap存储它们的key,value指向节点本身。查询时,只需要判断HashMap是否存在这个key,复杂度O(1),存在就直接获取到value也就是那个节点。所以我们将查询性能也提高到了O(1)。
使用了散列表提高了查询效率的同时,也同样多出了一些小小的问题。因为使用了散列表可以快速精准的定位某一个节点,但是我们要做的不只是将这个节点移动到头部,还需要将这个节点删除,也就是将上一个节点连接到下一个节点。(使用双向链表)
使用了双向链表就可以快速得到 查询到的节点的上一个节点,就可以将上一个节点的指向从该节点转变为下一个节点。
图解如下
![](https://i-blog.csdnimg.cn/blog_migrate/8cd29515adeb04dd0a7030696ac1ce1c.png)
第一次这么去写东西呀,可能出现考虑不周的地方,如果遇到不对的地方希望可以多多指正,谢谢大家~