title: 自己手写一个LRU策略
date: 2021-06-18 12:00:30
tags:
- [redis]
- [lru]
categories:
- [redis]
permalink: zxh
prefix: redis
一、题目描述
146. LRU 缓存机制
运用你所掌握的数据结构,设计和实现一个
LRU
(最近最少使用) 缓存机制 。
实现LRUCache
类:
LRUCache(int capacity)
以正整数作为容量 capacity 初始化LRU
缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
二、思路分析
第一想法
- 刚看到本题时没有多想就觉得会用到队列,因为队列FIFO可以做到淘汰末尾数据,但是仔细一想本题是需要淘汰最近最少使用数据,如果仅仅是最近的数据那么队列很容易实现。加上使用频率就涉及到数据的频繁挪动。很明显队列是无法完成的。
- 那么有没有一种顺序添加的数据,每次在获取之后就会将数据前移至一端呢?答案是有的!
LinkedHashMap
LinkedHashMap
不熟悉的朋友们可以简单的将它理解成HashMap
。 下图展示了HashMap
的存储结构
- 上述的元素我这里做了个动画演示全过程!!!
- 而
LinkedHashMap
只是多了一条链表串起里面的元素
- 这也是为什么
LinkedHashMap
是按照顺序存储的。但是LinkedHahsMap
也无法做到按照使用频率进行排序啊?大家都知道他是按照添加顺序排序的!!!
LinkedHashMap
改造
- 原生的
LinkedHashMap
的确无法满足情况,但是我们稍微看下源码能够发现在put之后都会执行下afterNodeInsertion
这个方法。这也是HashMap
留给LinkedHashMap
做的扩展!
removeNode
就是将最前面的数据。想要进入这个方法就需要removeEldestEntry
判断。LinkedHashMap
默认是false . 所以我们只需要重写他就行了。但是还是在get值的时候如何保值在最后面呢?我们仔细看下源码就能够发现在get
中有这个一个方法afterNodeAccess
。他的作用就是将get的元素移位值后面。正好符合我们LRU
的策略特征
- 综上!我们借助
LinkedHashMap
就非常容易的实现了LRU策略!
自己实现
-
但是本题的意思是想考察我们自己是如何实现的,而不是巧妙对现有的工具改造的!不过上面对
LinkedHashMap
的确改造的很巧这是不可否认的!下面我们就尝试自己来实现下这种方式! -
首先我们需要确定需要用到Hash结合链表来实现。Hash我们自然使用
HashMap
来存储数据为的就是方便定位数据。定位到数据就需要操作链表将数据实时移位值链表尾部,每次淘汰是将链表首位移除既可。为了方便我们操作链表这里的链表肯定是双链表的!
链表单元
- 在构建器中初始化容量和链表大小,并初始化边界节点方便我们操作节点中移位和删除。
方法名 | 作用 |
---|---|
addToTail | 将节点添加值链表尾部 |
movetoTail | 将已经存在于链表中的节点移动到链表的尾部 |
removeHeadNode | 删除链表中第一个节点,注意是边界节点后第一个节点 |
四、总结
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。