概念

  LRU(least recently used)就是将最近不被访问的数据给淘汰掉,LRU基于一种假设:认为最近使用过的数据将来被使用的概率也大,最近没有被访问的数据将来被使用的概率比较低。

原理

  LRU一般通过链表形式来存放缓存数据,新插入或被访问的数据放在链表头部,超过一定阈值后,自动淘汰链表尾部的数据。下图很形象的说明了LRU缓存淘汰过程。(图片来自网络)

步骤:

1、新插入A, 将A放置在队列头部

2、新插入B, 将B放置在队列头部, A自动推举次席。

3、新插入C, 将C放置在队列头部, B自动推举次席。

4、新插入D, 将D放置在队列头部, C自动推举次席。

5、新插入E, 将E放置在队列头部, D自动推举次席。

6、新插入E, 将E放置在队列头部, 这时队列长度大于阈值,自动将尾部数据A给淘汰掉

7、访问数据C,然后将C重新放置在队列头部。

8、新插入E, 将E放置在队列头部, 这时队列长度大于阈值,自动淘汰尾部数据B

编码实现LRU策略缓存

  1. /**
  2. * 2018/4/11.
  3. *
  4. * 使用链表+hashmap来实现, 这里没有考虑并发情况, 所以在代码中没有使用锁
  5. */
  6. public class LRUCache<K, V> {
  7.  
  8. class CacheNode {
  9. public CacheNode before;
  10. public Object key;
  11. public Object value;
  12. public CacheNode after;
  13.  
  14. public CacheNode() {
  15. }
  16. }
  17.  
  18. private HashMap<K, CacheNode> caches;
  19. private int maxCapacity;
  20. private int currentCacheSize;
  21. /**
  22. * 头结点, 头结点不参与淘汰,只是作为标识链表中的第一个节点
  23. */
  24. private CacheNode head;
  25. /**
  26. * 尾节点, 尾节点不参与淘汰, 只是作为标识链表中最后一个节点
  27. */
  28. private CacheNode tail;
  29.  
  30. public LRUCache(int maxCapacity) {
  31. this.maxCapacity = maxCapacity;
  32. caches = new HashMap<>(maxCapacity);
  33. head = tail = new CacheNode();
  34. head.after = tail; //对head 的after节点赋值, 防止后续操作出现空指针异常
  35. tail.before = head; // 对tail的before节点赋值, 防止后续操作出现空指针异常
  36. }
  37.  
  38. public void put(K k, V v) {
  39. CacheNode node = caches.get(k);
  40. if (node == null) {
  41. if (currentCacheSize >= maxCapacity) {
  42. caches.remove(tail.before.key); //淘汰尾部的元素
  43. removeLast();
  44. }
  45.  
  46. node = new CacheNode();
  47. node.key = k;
  48.  
  49. currentCacheSize ++;
  50. }
  51.  
  52. node.value = v;
  53. moveToFirst(node); // LRU策略, 新插入的元素放置到队列头部
  54. caches.put(k, node);
  55. }
  56.  
  57. public void moveToFirst(CacheNode node) {
  58. CacheNode n = head.after;
  59. head.after = node;
  60. node.before = head;
  61. n.before = node;
  62. node.after = n;
  63. }
  64.  
  65. public void removeLast() {
  66. CacheNode n = tail.before.before;
  67. n.after = tail;
  68. tail.before = n;
  69. }
  70.  
  71. public Object get(K k) {
  72. CacheNode node = caches.get(k);
  73. if (node == null) {
  74. return null;
  75. }
  76.  
  77. Object v = node.value;
  78. moveToFirst(node);
  79. return v;
  80. }
  81.  
  82. public Object remove(K k) {
  83. CacheNode node = caches.get(k);
  84. if (node == null) {
  85. return null;
  86. }
  87.  
  88. CacheNode pre = node.before;
  89. CacheNode next = node.after;
  90. pre.after = next;
  91. next.before = pre;
  92.  
  93. caches.remove(k);
  94.  
  95. currentCacheSize --;
  96. return node.value;
  97. }
  98. }

上述代码在博主本机测试验证通过(单线程操作下)

【面试题】LRU算法及编码实现LRU策略缓存的更多相关文章

  1. redis的LRU算法(一)

    最近加班比较累,完全不想写作了.. 刚看到一篇有趣的文章,是redis的作者antirez对redis的LRU算法的回顾.LRU算法是Least Recently Used的意思,将最近最少使用的资源 ...

  2. 【算法】LRU算法

    缓存一般存放的都是热点数据,而热点数据又是利用LRU(最近最久未用算法)对不断访问的数据筛选淘汰出来的. 出于对这个算法的好奇就查了下资料. LRU算法四种实现方式介绍 缓存淘汰算法 利用Linked ...

  3. LRU算法与LRUCache

    关于LRU LRU(Least recently used,最近最少使用)算法是操作系统中一种经典的页面置换算法,当发生缺页中断时,需要将内存的一个或几个页面置换出,LRU指出应该将内存最近最少使用的 ...

  4. 基于LinkedhashMap实现的LRU算法

    LRU全称是Least Recently Used,即最近最久未使用的意思.LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已存 ...

  5. Guava---缓存之LRU算法

    随笔 - 169  文章 - 0  评论 - 292 GuavaCache学习笔记一:自定义LRU算法的缓存实现   前言 今天在看GuavaCache缓存相关的源码,这里想到先自己手动实现一个LRU ...

  6. 【Redis 设置Redis使用LRU算法】

    转自:http://ifeve.com/redis-lru/ 本文将介绍Redis在生产环境中使用的Redis的LRU策略,以及自己动手实现的LRU算法(php) 1.设置Redis使用LRU算法 L ...

  7. Redis内存回收:LRU算法

    Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read Redis中采用两种算法进行内存回收,引用计数算法以及LRU ...

  8. FIFO调度算法和LRU算法

    一.理论 FIFO:先进先出调度算法 LRU:最近最久未使用调度算法 两者都是缓存调度算法,经常用作内存的页面置换算法. 打一个比方,帮助你理解.你有很多的书,比如说10000本.由于你的书实在太多了 ...

  9. LRU算法原理解析

    LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的. 现代操作系统提供了一种对主存的抽象概念虚拟内存,来对主存进行更好地管理.他将主存 ...

随机推荐

  1. 【SQL】从待选项中随机选一个

    由于SQL Server没有数组类型,所以在面对“从若干待选项中选一个”这种需求时,往往要采取变通办法,比如弄个‘a|b|c’这样的字符串然后对字符串进行处理:又或者把待选项塞进一个临时表,然后把问题 ...

  2. sql server 查看版本

    SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY ('productlevel'),SERVERPROPERTY ('edition') ...

  3. 使用Quartz实现定时作业

    该文章是系列文章 基于.NetCore和ABP框架如何让Windows服务执行Quartz定时作业 的其中一篇. Quartz是一个开源的作业调度框架,准确的称谓应该是 Quartz.Net,它是Ja ...

  4. centos 允许远程连接mysql

    GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;

  5. flask框架路由系统

    flask框架的url系统: flask框架的路由系统: flask框架的路由系统使用实例化的route方法来指定: 如: @app.route('/') route函数装饰器可以把一个函数绑定到对应 ...

  6. 455 Assign Cookies 分发饼干

    假设你是一位很棒的家长,想要给你的孩子们一些小饼干.但是,每个孩子最多只能给一块饼干.对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸:并且每块饼干 j ,都有一个尺寸 ...

  7. 201 Bitwise AND of Numbers Range 数字范围按位与

    给定范围 [m,n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含m, n两端点).例如,给定范围 [5,7],您应该返回 4. 详见 ...

  8. 分享一款强大的图片查看器插件,手机PC 通吃,功能超级齐全!

    一款强大的图片查看器插件,手机PC 通吃,功能超级齐全! 地址:http://photoswipe.com/

  9. PHP + ORACLE 远程连接数据库环境配置

    在ORACLE官网下载instantclient_11_2,放在D盘 把instantclient_11_2目录下的所有dll文件复制到C:\Windows\SysWOW64   和  D:\phpS ...

  10. Linux 之 2>&1

    我们在Linux下经常会碰到nohup command>/dev/null 2>&1 &这样形式的命令.首先我们把这条命令大概分解下首先就是一个nohup表示当前用户和系统 ...