LRU即是Least Recently Used,即最近最少使用,选择最近最久未使用的数据将其淘汰。

最简单的想法是使用先进先出(FIFO)的方式来实现,通过双向链表来实现

因为链表插入和删除快,但是查询慢 ,而 HashMap的查询速度快很多,所以除了构建一个双向链表,还构建了一个哈希map,用于快速查询对应key的节点,用空间换时间

每次key被访问的时候,把被访问到的key移到头节点,这样当添加新节点的时候,直接添加到头节点即可,如果缓存已满,直接删除尾节点就可以了

jdk里有提供现成的LinkedHashMap,采用HashMap+链表的方式自己实现了一下

/*** @Description* @Author chenpp* @Date 2019/11/21 17:50* 定义双向链表的节点*/
public class Node<K,V> {private K key;private V value;private Node next;private Node pre;public Node(K key,V value){this.key = key;this.value = value;}public K getKey() {return key;}public void setKey(K key) {this.key = key;}public V getValue() {return value;}public void setValue(V value) {this.value = value;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}public Node getPre() {return pre;}public void setPre(Node pre) {this.pre = pre;}
}

/*** @Description* @Author chenpp* @Date 2019/11/21 17:56* 定义一个双向链表*/
public class DoubleLinkedList<K,V> {transient Node<K,V> first;transient Node<K,V> last;/*** 当前链表里的节点数目* */transient int size;/*** 添加节点到链表头部* */public void addFirst(Node node) {if (first == null) {first = node;last = node;} else {Node oldFirst = first;oldFirst.setPre(node);node.setNext(oldFirst);first = node;}size++;}/*** 删除链表里已有的node节点** */private Node removeNode(Node node){if(node == null){return null;}Node preNode = node.getPre();Node nextNode = node.getNext();if(preNode != null) {preNode.setNext(nextNode);}else{first = nextNode;}if(nextNode != null){nextNode.setPre(preNode);}else{last = preNode;}size--;return node;}/*** 将链表指定节点node移动到头部** */public Node moveToHead(Node node){if(node == first){return node;}if( node == last){last = node.getPre();}else{node.getNext().setPre(node.getPre());}node.getPre().setNext(node.getNext());node.setPre(null);node.setNext(first);first = node;return node;}/*** 删除最后一个节点* 并返回删除的节点** */public Node removeLast(){Node node = last;removeNode(last);return node;}public int size(){return size;}
}

/*** @Description* @Author chenpp* @Date 2019/11/21 17:52* */
public class LRUCache<K,V> {private HashMap<K, Node<K,V>> linkedHashMap;private int capacity;private DoubleLinkedList linkedList;public LRUCache(int capacity){this.capacity = capacity;linkedList = new DoubleLinkedList();linkedHashMap = new HashMap<K, Node<K,V>>();}/*** 访问缓存指定的key* 将对应的node移动到链表头部** */public V get(K k){Node<K,V> node = linkedHashMap.get(k);if(node == null){return null;}//将访问的节点移动到头节点linkedList.moveToHead(node);return node.getValue();}/*** 新增node节点到链表头部* 如果缓存超过最大容量,则删除尾部节点** */public void put(K key,V val){Node node = linkedHashMap.get(key);//如果节点的key本来就存在,则直接移动到头节点if(node != null){node.setValue(val);node = linkedList.moveToHead(node);}else{node = new Node(key,val);//如果key不存在,则新增节点到头部if(linkedList.size() >= capacity){//移除访问时间最远的节点Node last = linkedList.removeLast();linkedHashMap.remove(last.getKey());}linkedList.addFirst(node);}//更新hashMap里的值linkedHashMap.put(key,node);}@Overridepublic String toString() {StringBuilder sb = new StringBuilder();Node node = linkedList.first;while(node != null){sb.append(String.format("%s:%s ", node.getKey(),node.getValue()));node = node.getNext();}return sb.toString();}}

测试一下:

/*** @Description* @Author chenpp* @Date 2019/11/21 19:49*/
public class Test {public static void main(String[] args) {LRUCache<String,String> cache = new LRUCache<String, String>(5);cache.put("a","111");cache.put("b","2121");cache.put("c","3231");cache.put("d","2122");cache.put("e","2131");cache.get("3");//e d c b aSystem.out.println(cache.toString());cache.get("a");// a e d c bSystem.out.println(cache.toString());cache.put("f","13123");// f a e d cSystem.out.println(cache.toString());cache.get("b");System.out.println(cache.toString());cache.get("a");// a f e d cSystem.out.println(cache.toString());cache.put("g","g");// g a f e dSystem.out.println(cache.toString());cache.put("c","31");// c g a f eSystem.out.println(cache.toString());cache.get("d");System.out.println(cache.toString());cache.get("c");System.out.println(cache.toString());}
}

HashMap+双向链表实现LRU相关推荐

  1. LRU(Least Recent Used) java实现——为什么采用HashMap+双向链表

    在知乎上看到一篇文章 : LRU原理和Redis实现--一个今日头条的面试题 他采用HashMap+双向链表实现LRU(淘汰掉最不经常使用的).先来将原文简单引用介绍下,以免原作者删除. 很久前参加过 ...

  2. hashmap是单向链表吗_LRU(Least Recent Used) java 实现为这么采用HashMap+双向链表

    他采用HashMap+双向链表实现LRU(淘汰掉最不经常使用的).先来将原文简单引用介绍下,以免原作者删除. 很久前参加过今日头条的面试,遇到一个题,目前半部分是如何实现 LRU,后半部分是 Redi ...

  3. 【文科生带你读JavaScript数据结构与算法】2. 双向链表与LRU缓存算法原理与实现(下)

    上篇聊了聊双向链表(doubly linked list)这个数据结构,今天就来点更实际的,也可以用双链表来实现的一种生活工作中不可或缺的优化算法--LRU缓存(Least Recently Used ...

  4. HashMap实现LRU(最近最少使用)缓存更新算法

    最近阿里巴巴电话面试被问到了如何使用固定容量的HashMap,实现LRU算法.当时一脸懵逼,平时用HashMap也就用来快速存取数据而已,容量都是不限的. 想了半天,想到对node节点进行扩展,加入引 ...

  5. 有关 HashMap 面试会问的一切

    来自:码农田小齐 本文共6666字 | 阅读需12分钟 前言 HashMap 是无论在工作还是面试中都非常常见常考的数据结构. 比如 Leetcode 第一题 Two Sum 的某种变种的最优解就是需 ...

  6. LRU原理及其实现(C++)

    LRU原理 在一般标准的操作系统教材里,会用下面的方式来演示 LRU 原理,假设内存只能容纳3个页大小,按照 7 0 1 2 0 3 0 4 的次序访问页.假设内存按照栈的方式来描述访问时间,在上面的 ...

  7. java mysql lru_Java集合详解5:深入理解LinkedHashMap和LRU缓存

    今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存. 摘要:HashMap和双向链表合二为一即是LinkedHashMap.所谓Linked ...

  8. 【039期】头条面试:说一说 LRU 原理和 Redis 如何实现?

    >>号外:关注"Java精选"公众号,回复"面试资料",免费领取资料!"Java精选面试题"小程序,3000+ 道面试题在线刷, ...

  9. 最近最少使用LRU(Least Recently Used)算法java实现

    最近最少使用LRU(Least Recently Used)算法java实现 一.使用LinkedHashMap算法实现 二.手撸 LRU 算法实现(Hash表 + 双向链表) 三.总结 最近最少使用 ...

最新文章

  1. python3.9.0 print_关于 Python 3.9,那些你不知道的事
  2. 电子学会青少年编程等级考试Python一级题目解析12
  3. Oracle 12c 新特性之 temp undo
  4. 给Python加Markdown式排版,在线运行可做Jupyter替身丨谷歌大脑出品
  5. lingo变量无限制版本_【运筹学】用Lingo求解运输问题,兼谈Lingo语法
  6. osgEarth使用没有DX的Triton库Triton-MT-DLL-NODX.lib
  7. java 爬虫_Java原生代码实现爬虫(爬取小说)
  8. Android 调试技巧之快速重启生效
  9. 基于nodejs的模拟数据分发服务
  10. QT实现简单的抽奖界面
  11. 公众号获取access_token失败
  12. 设计模式的艺术 结构性模式之组合模式
  13. python运行按钮灰色_点击后,tkinter菜单按钮变灰了
  14. c语言鞋码,童鞋尺码对照表 童鞋1c、2c、3c和4c是多大码 多少厘米
  15. Android视频资源下载链接
  16. k8s_难产的ingress架构初体验(一)
  17. Python之Flask入门教程
  18. excel表格下拉选项怎么设置_Excel表格怎么画任意划线
  19. XP局域网共享设置图文教程
  20. 计算机开机错误62,联想电脑开机显示Error 1962 no operating system解决方法

热门文章

  1. 【Homework】银行存取款业务
  2. 方法重写(override)注意事项和使用细节
  3. python实现一个商品管理_python编写商品管理
  4. PCB电流和线宽的关系(通俗易懂)
  5. 带你走进rsync的世界
  6. LAPM×××和php加速器
  7. find命令的技巧和一些例子
  8. java编程好文章链接收集
  9. linux基于usb启动配置
  10. 转贴——灰鸽子的危害超出‘熊猫烧香’10倍