LRU算法

  • 哈希链表
  • 自己的JAVA实现
    • 定义链表节点
    • 最底层
    • 中间层
    • 最上层

LRU全称Least Recently Used,也就是 最近最少使用的意思,是一种内存管理算法,该算法最早应用于Linux操作系统。

这个算法基于一种假设:长期不被使用的数据,在未来被用到的几率也不大。因此,当数据所占内存达到一定阈值时,我们要移除掉最近最少被使用的数据。

在LRU算法中,使用了哈希链表

哈希链表

哈希表是由若干个Key-Value组成的。在“逻辑”上,这些Key-Value是无所谓排列顺序的,谁先谁后都一样。

在哈希链表中,这些Key-Value不再是彼此无关的存在,而是被一个链条串了
起来。每一个Key-Value都具有它的前驱Key-Value、后继Key-Value,就像双向
链表中的节点一样。

原本无序的哈希表就拥有了固定的排列顺序
依靠哈希链表的有序性,我们可以把Key-Value按照最后的使用时间进行排序

将新插入的或者刚被访问的数据插入到链表的最右端
左端就是最近最少被访问的数据

假设这时缓存容量已经达到上限,必须先删除最近最少被访问的数据,那么位于哈希链表最左端的数据就会被删除,然后再把新数据插入最右端的位置。

LinkedHashMap已经实现了哈希链表

自己的JAVA实现

可以把LRU算法代码的构建类比为后端分层模型:持久层(Dao层)、业务层(Service层)、Servlet层

  1. 最底层就是链表
  2. 中间层就是用哈希map包装了链表操作(用哈希map的value存链表node)
  3. 最上层就是加上了LRU算法逻辑

定义链表节点

//链表节点class Node{public Node pre;public Node next;public String key;public String value;public Node(String key, String value) {this.key = key;this.value = value;}}

最底层

/*** 删除链表中任意位置的节点* @param node  要删除的节点* @return*/private String removeNode(Node node){if(node==head&&node==end){//链表只有一个元素,移除唯一的节点//头指针和尾指针都置空head=null;end=null;}else if(node==end){//移除尾节点end = end.pre;//尾指针前移一位end.next=null;}else if(node==head){//移除头节点head = head.next;//头指针后移一位head.pre = null;}else {//移除中间节点node.pre.next = node.next;node.next.pre = node.pre;}//将删除节点的key返回return node.key;}/*** 尾部插入节点* LRU算法每次都只能在尾部插入节点* 链表头部表示:最近最少使用的节点* @param node  要插入的节点*/private void addNode(Node node){if(end!=null){//链表有元素,则插入到end指针指向的元素后面end.next = node;node.pre = end;node.next = null;}//尾指针后移//不管之前链表有没有元素,node插入都将是链表最后一个元素end=node;if(head==null){//说明在没插入node之前是空链表//插入后只有node一个元素//node既是头也是尾head=node;}}/*** 刷新被访问的节点位置(就是再次访问链表中已经存在的元素,将他们放到链表尾)* @param node 被访问的节点*             这里Node node都是引用(node就是指针,指向node的指针)*             node和end,pre都是引用(指针)*/private void refreshNode(Node node){if(node==end){//访问的是尾节点,无需移动节点return;}//走到这一步都得把node指向的节点移动到链表尾//先删除这个节点removeNode(node);//在插入到尾部(尾插)addNode(node);}

中间层

//中间层***********/*** 从哈希map链表中删除key对应的value* 注意看传入参数* 其实本质就是链表指定位置的删除* 在外面套了一层哈希map的皮* @param key*/public void remove(String key){Node node =hashMap.get(key);removeNode(node);//链表中删除hashMap.remove(key);//哈希map中删除}/*** 从哈希map链表中添加key对应的value*  注意看传入参数*  其实本质就是链表尾插*  在外面套了一层哈希map的皮* @param key* @param value*/public void add(String key,String value){//新建链表节点Node node =new Node(key,value);//value本质保存到node中了addNode(node);//链表尾插hashMap.put(key,node);//哈希map中添加}

最上层

/*** 将key和value存入哈希map链表中..* 注意这里key和value都是String类型* 我们定义的:private HashMap<String,Node> hashMap;* @param key* @param value*/public void put(String key,String value){//获取HashMap中对应key值的valus//在LRU算法中,如果key对应的value不存在,则在链表末尾插入//如果key对应的value存在,则将该元素取出放到链表的末尾Node node = hashMap.get(key);//如果Key 不存在,则在末尾插入Key-Valueif(node==null){//哈希mao链表超过长度,移除头节点if(hashMap.size()>=limit){//头节点是最近最少使用的,移除String oldKey = removeNode(head);hashMap.remove(oldKey);}add(key,value);}else {//如果Key 存在,则刷新Key-Value(将其放入链表末尾)node.value = value;//更新值refreshNode(node);}}public String get(String key){Node node = hashMap.get(key);//没有存对应的key和valueif(node==null){String a="哈希链表没有 "+key+" 和与之对应的value";return a;}refreshNode(node);//将刚访问的节点放到链表末尾return node.value;}

测试方法:

public static void main(String[] args) {myLinkHashMap myLinkHashMap = new myLinkHashMap(4);myLinkHashMap.put("1","小红");myLinkHashMap.put("2","小明");myLinkHashMap.put("3","小强");System.out.println(myLinkHashMap.get("2"));System.out.println(myLinkHashMap.get("4"));myLinkHashMap.put("4","王丽");System.out.println(myLinkHashMap.get("4"));myLinkHashMap.put("5","小刚");System.out.println(myLinkHashMap.get("1"));}


可以看到,最近最少被使用的key="1"被LRU算法删除了。

完整代码:

package practice;import java.util.HashMap;public class myLinkHashMap {//链表节点class Node{public Node pre;public Node next;public String key;public String value;public Node(String key, String value) {this.key = key;this.value = value;}}private Node head;//头指针private Node end;//尾指针private int limit;//最大存储的链表节点数目(缓存存储上限)//注意这里的value是Node类型的//虽然用HashMap(无序的)存储的,但value是node类型,通过指针就把不同的value串联起来了private HashMap<String,Node> hashMap;public myLinkHashMap(int limit){this.limit = limit;hashMap = new HashMap<String,Node>();}//最底层************/*** 删除链表中任意位置的节点* @param node  要删除的节点* @return*/private String removeNode(Node node){if(node==head&&node==end){//链表只有一个元素,移除唯一的节点//头指针和尾指针都置空head=null;end=null;}else if(node==end){//移除尾节点end = end.pre;//尾指针前移一位end.next=null;}else if(node==head){//移除头节点head = head.next;//头指针后移一位head.pre = null;}else {//移除中间节点node.pre.next = node.next;node.next.pre = node.pre;}//将删除节点的key返回return node.key;}/*** 尾部插入节点* LRU算法每次都只能在尾部插入节点* 链表头部表示:最近最少使用的节点* @param node  要插入的节点*/private void addNode(Node node){if(end!=null){//链表有元素,则插入到end指针指向的元素后面end.next = node;node.pre = end;node.next = null;}//尾指针后移//不管之前链表有没有元素,node插入都将是链表最后一个元素end=node;if(head==null){//说明在没插入node之前是空链表//插入后只有node一个元素//node既是头也是尾head=node;}}/*** 刷新被访问的节点位置(就是再次访问链表中已经存在的元素,将他们放到链表尾)* @param node 被访问的节点*             这里Node node都是引用(node就是指针,指向node的指针)*             node和end,pre都是引用(指针)*/private void refreshNode(Node node){if(node==end){//访问的是尾节点,无需移动节点return;}//走到这一步都得把node指向的节点移动到链表尾//先删除这个节点removeNode(node);//在插入到尾部(尾插)addNode(node);}//中间层***********/*** 从哈希map链表中删除key对应的value* 注意看传入参数* 其实本质就是链表指定位置的删除* 在外面套了一层哈希map的皮* @param key*/public void remove(String key){Node node =hashMap.get(key);removeNode(node);//链表中删除hashMap.remove(key);//哈希map中删除}/*** 从哈希map链表中添加key对应的value*  注意看传入参数*  其实本质就是链表尾插*  在外面套了一层哈希map的皮* @param key* @param value*/public void add(String key,String value){//新建链表节点Node node =new Node(key,value);//value本质保存到node中了addNode(node);//链表尾插hashMap.put(key,node);//哈希map中添加}//最上层****************/*** 将key和value存入哈希map链表中..* 注意这里key和value都是String类型* 我们定义的:private HashMap<String,Node> hashMap;* @param key* @param value*/public void put(String key,String value){//获取HashMap中对应key值的valus//在LRU算法中,如果key对应的value不存在,则在链表末尾插入//如果key对应的value存在,则将该元素取出放到链表的末尾Node node = hashMap.get(key);//如果Key 不存在,则在末尾插入Key-Valueif(node==null){//哈希mao链表超过长度,移除头节点if(hashMap.size()>=limit){//头节点是最近最少使用的,移除String oldKey = removeNode(head);hashMap.remove(oldKey);}add(key,value);}else {//如果Key 存在,则刷新Key-Value(将其放入链表末尾)node.value = value;//更新值refreshNode(node);}}public String get(String key){Node node = hashMap.get(key);//没有存对应的key和valueif(node==null){String a="哈希链表没有 "+key+" 和与之对应的value";return a;}refreshNode(node);//将刚访问的节点放到链表末尾return node.value;}public static void main(String[] args) {myLinkHashMap myLinkHashMap = new myLinkHashMap(4);myLinkHashMap.put("1","小红");myLinkHashMap.put("2","小明");myLinkHashMap.put("3","小强");System.out.println(myLinkHashMap.get("2"));System.out.println(myLinkHashMap.get("4"));myLinkHashMap.put("4","王丽");System.out.println(myLinkHashMap.get("4"));myLinkHashMap.put("5","小刚");System.out.println(myLinkHashMap.get("1"));}}

数据结构---LRU算法相关推荐

  1. 数据结构与算法 / LRU 缓存淘汰算法

    一.诞生原因 缓存是一种提供数据读取性能的技术,在硬件设计.软件开发中有广泛的应用,比如常见的 CPU 缓存,DB 缓存和浏览器缓存等.但是缓存的大小是有限的,需要一定的机制判断哪些数据需要淘汰,即: ...

  2. LRU算法 -- 链表 完整实现

    LRU算法(Least Recently Used) 算是我们经常遇到的一种淘汰算法,其中内存管理模块进行内存页回收时有用到,针对不经常使用的内存页,LRU淘汰策略能够将该内存页回收给操作系统. 属于 ...

  3. 漫画:什么是LRU算法?

    本期封面作者:A17 -----  两个月前  ----- 用户信息当然是存在数据库里.但是由于我们对用户系统的性能要求比较高,显然不能每一次请求都去查询数据库. 所以,小灰在内存中创建了一个哈希表作 ...

  4. 【腾讯三面】你能现场写一下LRU算法吗?

    " 金三银四,又到了换工作的黄金期.各位小伙伴们都准备好了吗? " 这句话大家是不是最近已经要看吐了呢? 每当这个时候,就证明招聘旺季又来啦~ 春招.校招.社招-- 那你真的准备好 ...

  5. java 最少使用(lru)置换算法_「面试」LRU了解么?看看LinkedHashMap如何实现LRU算法...

    以下内容均是本人原创,希望你看完之后能有更多更深入的了解,欢迎关注➕ 问题:使用Java完成一个简单的LRU算法 什么是LRU算法 LRU(Least Recently Used),也就是最近最少使用 ...

  6. Java数据结构和算法:HashMap的实现原理

    HashMap源码理解 Java集合之HashMap HashMap原理及实现学习总结 HashMap源码分析 HashMap原理及实现学习总结 1. HashMap概述 HashMap是基于哈希表的 ...

  7. 2.LRU算法实现 [C++]

    LRU算法实现原理: 最近最久未使用页面置换算法(LRU) 当需要淘汰某一页时,选择在最近一段时间里最久没有被使用过的页淘汰. 其基本原理为:如果某一个页面被访问了,它很可能还要被访问:相反,如果它长 ...

  8. 操作系统之存储管理——FIFO算法和LRU算法

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  9. 数据结构与算法必备的 50 个代码实现

    点击上方"AI有道",选择"置顶"公众号 重磅干货,第一时间送达 数据结构和算法是程序员的内功心法和基本功.无论是人工智能还是其它计算机科学领域,掌握扎实的数据 ...

最新文章

  1. matlab固定床反应器,合成气完全甲烷化固定床反应器数值模拟
  2. tnsnames.ora和listener.ora文件中的几个概念
  3. shiro realm 注解失败问题解决过程
  4. [Leetcode]50. Pow(x, n)
  5. 前端学习(1164):剩余参数02
  6. 按下组合键 可以迅速锁定计算机,Win7锁定计算机快捷键是什么?Win7使用锁定计算机快捷键的方法...
  7. Spring Cloud 各个组件介绍
  8. php 数据分流,php实现请求分流 - osc_6fvwlc7h的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. python多进程调试_使用pyrasite进行python进程调试,改变运行中进程的代码
  10. 使用信息架构视图访问数据库元数据
  11. atitit.session的原理以及设计 java php实现的异同
  12. Instant Run 的操作影响到了代码,导致Android App启动闪退的问题
  13. CloudSim源码分析之DatacenterBroker--processEvent()
  14. 软件定义的网络(下)
  15. sqlmap总出现missing a mandatory option的解决方法
  16. C++知识库(可能包含一些非C++这门语言的知识体系、Java知识)
  17. winXP SP2体验
  18. js祝愿墙百度云_拒绝的祝福(或超越“否”)
  19. 脱离微信运行环境,小程序如何实现微信授权登录
  20. ov9712雄迈模组分析

热门文章

  1. HadoopRPC原理
  2. SQL Server创建表和添加列
  3. Java中super关键字及其作用
  4. 简历通过率从40%直升100%,我是这样做的
  5. Adaptive Two-Stage Filter for De-snowing LiDAR Point Clouds(DNNOR)
  6. いたずら極悪 +イチャずら+かすたむアイドロイドAi 转区破解+界面汉化补丁
  7. Springc中的IOC控制反转c01
  8. C++ 动态链接库和静态链接库
  9. c++基础:之泛型与标准模板库
  10. C#——关闭窗口的方法——vs