LRU缓存的实现
LRU简介
LRU是“Least Recently Used”的简写,意思是最近最少使用,是一种缓存淘汰策略,在有限的缓存资源中,淘汰掉最近最久未使用的。例如:缓存最大容纳10000条数据,在添加时,只要数据总数小于等于10000可以随意添加,但是当数据量大于1万时,将旧的数据删除,再添加新的数据;添加时,要将新来的数据添加到最前面。说完来添加,再来说查询,从缓存中获取的数据返回之前,需要将数据移动到最前面,因为获取改数据就代表最近使用了,对于缓存来说,最近这个数据很有可能会被再次使用,所以要移动到最前面。

LRU算法分析
因为缓存具有查询快(时间复杂度必须是O(1)),增加快,删除快的特点。同时,LRU策略分析的数据有新旧之分,新的在最前面,旧的往后放。因此选取数据结构时,要遵循有序的特点。因此可以将HashMap与双向链表结合起来实现LRUCache。Hash表查询效率是O(1),但是不是有序的,双向链表(此处不是循环链表)有序并且增加与删除都是O(1),但查询是O(n),所以两者互相取长补短。

实现代码
节点类
public class Node {
public int key,value;
public Node prev;
public Node next;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"key=" + key +
", value=" + value +
'}';
}
}
双向链表
public class DoubleList {
private LinkedList<Node> linkedList = new LinkedList();
/**添加第一个节点
* @param node
*/
public void addFirst(Node node){
linkedList.addFirst(node);
}
/**
*移除最后一个节点
*/
public Node removeLast(){
return linkedList.removeLast();
}
/**
*移除节点
*/
public void remove(Node node){
linkedList.remove(node);
}
/**
* 链表长度
* @return
*/
public int size(){
return linkedList.size();
}
/**
* 输出双向链表
*/
public void printAll(){
Iterator<Node> iterator = linkedList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
LRUCache类
public class LRUCache {
private HashMap<Integer, Node> map;
private DoubleList cache;
private int cap;
public LRUCache( int cap) {
this.map = new HashMap<Integer, Node>();
this.cache = new DoubleList();
this.cap = cap;
}
/**
* 查询value
**/
public int get(int key){
// 首先判断key是否在map中
if (map.containsKey(key)){
int x = map.get(key).value;
// 在返回之前,将最近访问的键值对添加到LRU中
put(key,x);
return x;
}else {
// 不存在返回-1
return -1;
}
}
// 新增键值对
public void put(int key,int value){
Node node = new Node(key, value);
// 首先判断key是否在map中,如果已存在,map直接新增,覆盖旧的value
if (map.containsKey(key)){
// 链表中删除旧的节点,在头部添加新的节点
cache.remove(map.get(key));
cache.addFirst(node);
map.put(key,node);
}else{
// 在向LRU添加key时,如果缓存已满,要删除最后一个Node,同时map中也要记得删除该key
if (cache.size()==cap){
Node last = cache.removeLast();
map.remove(last.key);
}
cache.addFirst(node);
map.put(key,node);
}
}
// 输出缓存中的数据
public void listAll(){
cache.printAll();
}
}
测试类
class LRUCacheTest {
private LRUCache lruCache = new LRUCache(4);
@Test
public void LRUCacheTest() {
lruCache.put(1, 2);
lruCache.put(2, 3);
lruCache.put(3, 4);
lruCache.put(5, 6);
// 因为cache大小是4,再添加新的数据时,会将最早加入缓存的数据淘汰掉
lruCache.put(6, 67);
// 获取第二次添加的数据,获取后(2,3)会被移动到最前边
lruCache.get(2);
lruCache.listAll();
}
}
所以输出结果:

总结
对于LRU算法,他的优势在于对热点数据的查询,使用LRU可以有效提高查询效率,但是对于批量查询历史数据,有可能导致缓存污染,偶然的查询历史数据,会覆盖掉热点数据,导致本次查询不再走缓存。
LRU缓存的实现的更多相关文章
- LRU缓存实现(Java)
LRU Cache的LinkedHashMap实现 LRU Cache的链表+HashMap实现 LinkedHashMap的FIFO实现 调用示例 LRU是Least Recently Used 的 ...
- 转: LRU缓存介绍与实现 (Java)
引子: 我们平时总会有一个电话本记录所有朋友的电话,但是,如果有朋友经常联系,那些朋友的电话号码不用翻电话本我们也能记住,但是,如果长时间没有联系了,要再次联系那位朋友的时候,我们又不得不求助电话本, ...
- volley三种基本请求图片的方式与Lru的基本使用:正常的加载+含有Lru缓存的加载+Volley控件networkImageview的使用
首先做出全局的请求队列 package com.qg.lizhanqi.myvolleydemo; import android.app.Application; import com.android ...
- 如何用LinkedHashMap实现LRU缓存算法
阿里巴巴笔试考到了LRU,一激动忘了怎么回事了..准备不充分啊.. 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的.LRU这个算法就是把最近一次 ...
- 面试挂在了 LRU 缓存算法设计上
好吧,有人可能觉得我标题党了,但我想告诉你们的是,前阵子面试确实挂在了 RLU 缓存算法的设计上了.当时做题的时候,自己想的太多了,感觉设计一个 LRU(Least recently used) 缓存 ...
- Java集合详解5:深入理解LinkedHashMap和LRU缓存
今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存. 摘要: HashMap和双向链表合二为一即是LinkedHashMap.所谓Linke ...
- 04 | 链表(上):如何实现LRU缓存淘汰算法?
今天我们来聊聊“链表(Linked list)”这个数据结构.学习链表有什么用呢?为了回答这个问题,我们先来讨论一个经典的链表应用场景,那就是+LRU+缓存淘汰算法. 缓存是一种提高数据读取性能的技术 ...
- LRU缓存原理
LRU(Least Recently Used) LRU是近期最少使用的算法,它的核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象. 采用LRU算法的缓存有两种:LrhCache和DisL ...
- 链表(上):如何实现LRU缓存淘汰算法?
一.什么是链表 和数组一样,链表也是一种线性表. 从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构. 链表中的每一个内存块被称为节点Node. ...
- [Leetcode]146.LRU缓存机制
Leetcode难题,题目为: 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制.它应该支持以下操作: 获取数据 get 和 写入数据 put . 获取数据 get(key ...
随机推荐
- 题解 P5401 [CTS2019]珍珠
蒟蒻语 这题太玄学了,蒟蒻写篇题解来让之后复习 = = 蒟蒻解 假设第 \(i\) 个颜色有 \(cnt_i\) 个珍珠. \(\sum\limits_{i=1}^{n} \left\lfloor\f ...
- VS调试相关
1.查看DataSet的数据
- 手把手教你:将 ClickHouse 集群迁至云上
前言 随着云上 ClickHouse 服务完善,越来越多的用户将自建 ClickHouse 服务迁移至云上.对于不同数据规模,我们选择不同的方案: 对于数据量比较小的表,通常小于10GB 情况下,可以 ...
- JUC(一):volatile关键字
volatile是什么 volatile是java虚拟机提供的轻量级同步机制,它包含三种特性: 保证可见性:只要主内存中变量做出修改,其余线程马上会感知到变量的修改. package com.ch ...
- Exception in thread "main" java.lang.NoSuchMethodError: scala.collection.immutable.HashSet$.empty()Lscala/collection/immutable/HashSet;
注意spark的Scala版本和java版本 修改后为官方指定的版本正常运行 Error:scalac: Error: object FloatRef does not have a member c ...
- css 09-CSS案例讲解:博雅互动
09-CSS案例讲解:博雅互动 #前言 CSS已经学了一些基础内容了,我们来讲解一个小案例吧.以博雅互动的官网首页举例. #版心 首页的版心如下: 这里我们要普及一个概念,叫"版心" ...
- Python高级语法-私有属性-魔法属性(4.7.2)
@ 目录 1.说明 2.代码 关于作者 1.说明 常用的一些魔法方法如下 所谓魔法方法,就是调用的时候 不好好正常调用 2.代码 class Test: """ 我是__ ...
- 基于Python实现环形队列高效定时器
定时器Python实现代码 import time import redis import multiprocessing class Base: """ redis配置 ...
- 官方VisualStudio.gitignore配置
官方地址 https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 示例 ## Ignore Visual Stud ...
- 如何查看打印机的IP地址和MAC地址
1. 打开控制面板,选择设备和打印机: 2. 选中打印机,右键单机,选择打印机 "属性": 3. 选择web服务,可以直接查看打印机的IP地址或MAC地址,如下图所示: 4. ...