数据结构与算法--如何实现LRU缓存淘汰算法

基于链表实现

我们维护一个有序的单链表,越靠近链表尾部的越是越早之前访问的,当有一个新的数据访问时,我们从头遍历链表

1 如果此数据之前已经被缓存到了链表中,我们遍历得到这个数据节点,然后从原位置删除,插入到链表的头部

2 如果此数据没有缓存到链表中,分为俩种情况
2.1 如果此时链表未满,就将此节点缓存到链表头
2.2 如果此时缓存已经满了,则把链表尾节点删除,再将新的数据添加到头结点。
这就是一个简单的LRU缓存,这种情况不管有没有满,都要遍历一遍链表,所以时间复杂度为O(n),我们还可以利用散列表优化

基于散列表实现

一个LRU缓存算法主要包括以下操作
1 向缓存里添加一个数据
2 从缓存里删除一个数据
3 从缓存里查找一个数据
这三个操作都涉及查找操作,如果单纯的用链表只能是O(n),如果我们将链表和散列表结合,就可以做到O(1),具体的数据结构如下面
在这里插入图片描述
我们使用双向链表储存数据,链表中每个节点储存数据data,前驱指针prve和后继指针next之外,还储存了一个hnext,那hnext有什么作用呢?

因为散列表是通过链表法,解决散列冲突的,所以每个节点会存在俩条链中,一条就是散列表中的双向链表,另一条就是我们的拉链,前序指针和后续指针是为了将结点串在双向链表中,hnext是为了串在拉链中

这个数据结构,查找一个数据,通过散列表去查找,时间复杂度为O(1)
这个数据结构,删除这个数据,首先我们要找到这个数据的节点,可以通过散列表查找,时间复杂度为O(1),然后删除,因为是双向链表,可以找到前驱指针,所以可以O(1),删除数据
这个数据结构,添加一个数据,首先我们要查找这个数据是否在缓存中通过散列表查O(1),如果在其中,把它移到双链表的尾部O(1),如果不在其中,看缓存是否已满,如果已经满了,就把头部结点删除O(1),把新数据加入到尾部O(1),如果没有满,就直接假如到尾部O(1)

这样就通过散列表和链表,实现了一个高效,支持LRU算法的缓存系统原型

java 的LinkedHashMap

我们知道HashMap是由散列表实现的,那么LinkedHashMap多了一个Linked,指的是什么?
其实LinkedHashMap的Linked是指双链表,他支持插入顺序遍历数据,还支持访问顺序遍历数据,也就是说LinkedHashMap本身就是支持LRU缓存算法的
实际上LinkedHashMap是通过散列表和双链表俩种数据结构结合实现的,其实LinkedHashMap的Linked是指双链表,并不是治链表法解决散列冲突

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值