【算法刷题】手撕LRU算法(原理、图解、核心思想)

在这里插入图片描述

文章目录

  • 1.LRU算法
    • 1.1相关概念
    • 1.2图解举例
    • 1.3基于HashMap和双向链表实现
      • 1.3.1核心思想
      • 1.3.2代码解读
      • 1.3.3全部代码

1.LRU算法

1.1相关概念

  • LRU(Least Recently Used,最近最久未使用算法):
    • 定义:根据页面调入内存后的使用情况来做决策。LRU页面置换算法选择最近最久未使用的页面予以淘汰;
    • 支持:该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问内以来锁经历的时间t;当淘汰一个页面时,选择现有页面中 t值最大的(即最近最久未使用的)页面进行淘汰
  • 两种硬件支持(选择其中一种即可):
    1. 寄存器:
      • 作用:其中包含了标记位和时间戳,标记位可以快速判断缓存块(页面)是否有效,而无需遍历整个栈来查找。时间戳可以快速记录和更新缓存块(页面)的访问时间,而不必每次访问都遍历栈来更新。
    2. 栈:
      • 作用:用于记录缓存块(页面)的访问顺序(当前使用中的各个页面的页面号)。
      • 新增页面步骤:
        • 每当进程访问某页面时,判断该页面在栈中是否存在
          • 若存在,则将该页面的页面号从栈中取出,并将该原页面号压入栈顶;
          • 若不存在,则将栈底元素移除,并将新页面号压入栈顶;
        • 因此,栈顶始终是最新被访问页面的页面号 , 栈底则是最近最久未使用页面的页面号!

1.2图解举例

  • 举例前提:假设内存只能容纳3个页大小,进程按照 5 2 1 9 2 0 2 8的次序访问页
  • 假设内存按照栈的方式来描述访问时间,并保证 栈顶始终是最新被访问页面的页面号 , 栈底则是最近最久未使用页面的页面号

image-20240419170652555

1.3基于HashMap和双向链表实现

1.3.1核心思想

  • 核心思想:使用自定义节点DLinkedNode模拟双向链表,并通过双向链表实现栈功能;

  • 使用HashMap存储以页面号为key,value存储指向双向链表节点的指针

  • 双向链表维护了页面的访问顺序,链表的头部(即栈顶)为最新访问的页面,底部为最久未使用的页面

  • put(key,value):首先在 HashMap 找到 Key 对应的节点,

    • 如果节点存在,更新节点的值,并把这个节点移动栈顶
    • 如果不存在,需要构造新的节点,并且尝试把节点塞到栈顶 ,如果LRU空间不足,则通过 tail 淘汰掉栈底的节点,同时在 HashMap 中移除 Key。

image-20240419175738628

1.3.2代码解读

  • DLinkedNode
class DLinkedNode {String key;int value;DLinkedNode pre;DLinkedNode next;
}
  • cache:使用HashTable代替HashMap,线程安全
private Hashtable<String, DLinkedNode> cache = new Hashtable<>();
  • put流程:
public void put(String key, int value) {DLinkedNode node = cache.get(key);if(node == null){DLinkedNode newNode = new DLinkedNode();newNode.key = key;newNode.value = value;this.cache.put(key, newNode);this.addNode(newNode);++count;if(count > capacity){// 淘汰栈底元素DLinkedNode tail = this.popTail();this.cache.remove(tail.key);--count;}}else{//该元素已经存在//将该元素移动到栈顶node.value = value;this.moveToHead(node);}
}
  • 移动栈中的元素到栈顶:
    • 首先先删除该节点 (解除引用)
    • 再添加该节点到栈顶
//将该节点移动到头节点
private void moveToHead(DLinkedNode node){this.removeNode(node);this.addNode(node);
}
//删除该节点(跳过该节点)
private void removeNode(DLinkedNode node){DLinkedNode pre = node.pre;DLinkedNode next = node.next;pre.next = next;next.pre = pre;
}
//添加节点到栈顶
private void addNode(DLinkedNode node){node.pre = head;node.next = head.next;head.next.pre = node;	//头部节点的上一个节点为新节点head.next = node;
}

1.3.3全部代码

class DLinkedNode {String key;int value;DLinkedNode pre;DLinkedNode next;
}public class LRUCache {private Hashtable<String, DLinkedNode> cache = new Hashtable<>();private int count;private int capacity;private DLinkedNode head, tail;public LRUCache(int capacity) {this.count = 0;this.capacity = capacity;head = new DLinkedNode();head.pre = null;tail = new DLinkedNode();tail.next = null;head.next = tail;tail.pre = head;}public void put(String key, int value) {DLinkedNode node = cache.get(key);if(node == null){DLinkedNode newNode = new DLinkedNode();newNode.key = key;newNode.value = value;this.cache.put(key, newNode);this.addNode(newNode);++count;if(count > capacity){// 淘汰栈底元素DLinkedNode tail = this.popTail();this.cache.remove(tail.key);--count;}}else{//该元素已经存在//将该元素移动到栈顶node.value = value;this.moveToHead(node);}}//添加节点private void addNode(DLinkedNode node){node.pre = head;node.next = head.next;head.next.pre = node;head.next = node;}//删除该节点(跳过该节点)private void removeNode(DLinkedNode node){DLinkedNode pre = node.pre;DLinkedNode next = node.next;pre.next = next;next.pre = pre;}//将该节点移动到头节点private void moveToHead(DLinkedNode node){this.removeNode(node);this.addNode(node);}//淘汰栈底元素private DLinkedNode popTail(){DLinkedNode res = tail.pre;this.removeNode(res);return res;}@Overridepublic String toString() {StringBuilder sbu = new StringBuilder();DLinkedNode cur = head.next;sbu.append("{");while (cur != tail) {if (cur.next != tail) {sbu.append(cur.key).append("=").append(cur.value).append(", ");} else {sbu.append(cur.key).append("=").append(cur.value);}cur = cur.next;}sbu.append("}");return sbu.toString();}public static void main(String[] args) {LRUCache lruCache = new LRUCache(3);lruCache.put("1", 5);lruCache.put("2", 2);lruCache.put("3", 1);System.out.println(lruCache);System.out.println("使用后:");lruCache.put("2",2);System.out.println(lruCache);lruCache.put("2",2);System.out.println(lruCache);lruCache.put("4", 13);System.out.println("最不常用的被删除,新元素插到头部:");System.out.println(lruCache);}}
  • 测试结果:

image-20240419181126783

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/2116.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(一)、SQL进阶——神奇的SQL

一、CASE表达式 1、CASE表达式概述 case表达式有简单case表达式和搜索case表达式两种写法 -- 简单case表达式 case sex when 1 then 男 when 0 then 女 else 其他 end -- 搜索case表达式 case when sex1 then 男 when sex1 then 男 else 其他 end 这两种写法执行的结…

跨平台手机号:微信手机号授权登录、微信授权登录双登录实现账户生态融合,新时代的身份密钥

小程序厂商的多样性体现在开发工具、服务领域、商业模式等多方面&#xff0c;各厂商凭借独特的技术优势、行业解决方案和市场策略&#xff0c;满足不同企业和用户需求。与此同时&#xff0c;随着移动互联网发展&#xff0c;手机号统一登录成为提升用户体验、简化登录流程的关键…

要养生也要时尚,益百分满足你的所有需求

要养生也要时尚&#xff0c;益百分满足你的所有需求 艾灸是个好东西&#xff0c;尤其是在近几年的时候&#xff0c;艾灸就像一阵浪潮席卷进了人们的日常生活之中&#xff0c;我们可以在街边看到大大小小的艾灸馆&#xff0c;有些评价比较高的艾灸馆门前甚至还排起了长长的队伍…

FasterViT:英伟达提出分层注意力,构造高吞吐CNN-ViT混合网络 | ICLR 2024

论文设计了新的CNN-ViT混合神经网络FasterViT&#xff0c;重点关注计算机视觉应用的图像吞吐能力。FasterViT结合CNN的局部特征学习的特性和ViT的全局建模特性&#xff0c;引入分层注意力&#xff08;HAT&#xff09;方法在降低计算成本的同时增加窗口间的交互。在包括分类、对…

【InternLM 实战营第二期笔记】Lagent AgentLego 智能体应用搭建

理论知识 Lagent 是什么 Lagent 是一个轻量级开源智能体框架&#xff0c;旨在让用户可以高效地构建基于大语言模型的智能体。同时它也提供了一些典型工具以增强大语言模型的能力。 Lagent 目前已经支持了包括 AutoGPT、ReAct 等在内的多个经典智能体范式&#xff0c;也支持了…

C语言指针+-整数、指针-指针、指针关系运算、指针和数组、二级指针、指针数组

文章目录 前言一、指针 - 整数二、指针 - 指针三、指针的关系运算四、指针和数组五、二级指针六、指针数组指针数组可以将几个一维数组模拟成二维数组 总结 前言 C语言指针整数、指针-指针、指针关系运算、指针和数组、二级指针、指针数组等介绍&#xff0c;还包括指针数组将几…

武汉大学博士,华为上班5年多,月薪多少。。。

最近&#xff0c;一位来自武汉大学的博士研究生透露了自己在华为公司工作五年后的薪酬情况。 据他透露&#xff0c;他在2018年加入华为时的月薪为2.4万&#xff0c;随着时间的推移&#xff0c;到了2023年&#xff0c;他的月薪已经增长至4.4万&#xff01;此外&#xff0c;他还透…

AI时代的GPU集群网络算力分析

浅谈GPU集群网络、集群规模和集群算力 引言在生成式AI&#xff08;GenAI&#xff09;和大模型时代&#xff0c;不仅需要关注单个GPU卡的算力&#xff0c;更要关注GPU集群的总有效算力。单个GPU卡的有效算力可以通过该卡的峰值算力来测算&#xff0c;例如&#xff0c;对于Nvidia…

网络工程师----第十一天

OSPF&#xff1a; 对称加密算法&#xff1a; 也称为私钥加密或单密钥算法&#xff0c;是一种加密方式&#xff0c;其中加密和解密使用相同的密钥。这种算法的优点包括加密解密速度快、计算量小&#xff0c;适用于大量数据的加密。然而&#xff0c;它的缺点是密钥的安全性难以保…

深度相机(3D相机)

传统的RGB彩色相机称为2D相机&#xff0c; 只能得到2D的图像信息&#xff0c; 无法得到物体与相机的距离信息&#xff0c;也就是深度信息。 顾名思义&#xff0c; 深度相机除了获取2D信息&#xff0c;还能得到深度信息&#xff0c;也叫RGBD相机&#xff0c; 或3D相机。 顺便提…

被删除的照片和视频能找回吗?如何恢复手机删除的照片和视频?

手机里的照片和视频是我们记录生活的每一个瞬间&#xff0c;也是工作学习等场合经常用到的东西&#xff0c;一旦不慎丢失&#xff0c;将对我们造成很大损失。那么我们该如何恢复手机删除的照片和视频呢&#xff1f;通过掌握正确的恢复方法&#xff0c;能够最大程度地保护手机中…

网络常识!!!

网络常识!!! 一:网络的发展史二:关键的概念三:IP地址四:端口号二级目录二级目录二级目录二级目录三级目录 一:网络的发展史 从游戏方面发展历程进行理解: 从单机游戏-----游戏支持局域网对战-------游戏支持广域网对战-------移动端 (1)局域网对战:在同一个网吧里,不同的游戏…

2016年新华三杯复赛实验试题

2016年新华三杯复赛实验试题 拓扑图 配置需求 考生根据以下配置需求在 HCL 中的设备上进行相关配置。 以太网接口配置 将 S1、S2 的以太网接口 G1/0/1 至 G1/0/16 的模式用命令 combo enable copper 激活为电口。 虚拟局域网 为了减少广播&#xff0c;需要规划并配置 VLA…

Seurat -- Introduction to scRNA-seq integration 跟随学习记录

文章目录 数据是如何转换的原始ifnb数据对象Splits object后的数据对象数据对象构建完成后的标准流程Normalization后的数据对象scale 后的数据对象 不同的样本进行整合JoinLayers干了什么 数据是如何转换的 seurat object 中assays R N A l a y e r s RNAlayers RNAlayersco…

新的全息技术突破计算障碍

一种突破性的方法利用基于Lohmann透镜的衍射模型实时创建计算机生成全息图&#xff08;CGH&#xff09;&#xff0c;在保持3D可视化质量的同时&#xff0c;大大降低了计算负荷要求。 全息显示为制作逼真的三维图像提供了一条令人兴奋的途径&#xff0c;这种图像给人以连续深度…

在 Slurm 上运行 Jupyter

1. 背景介绍 现在的大模型训练越来越深入每个组了&#xff0c;大规模集群系统也应用的愈发广泛。一般的slurm系统提交作业分为2种&#xff0c;一种是srun&#xff0c;这种所见即所得的申请方式一般适用于短期的调试使用&#xff0c;大概一般允许的时间从几个小时到1天左右&…

flutter 设置启屏页 flutter_native_splash 坑记录

flutter_native_splash | Flutter packageCustomize Flutters default white native splash screen with background color and splash image. Supports dark mode, full screen, and more.https://pub.dev/packages/flutter_native_splash 发现一直白屏 原因是 代码中 下面…

图书租赁系统

网上出版的电子书只有购买服务&#xff0c;如果也有租赁服务就好了。例如&#xff0c;读者可以租个1个小时&#xff0c;1个小时到期&#xff0c;读者就不能阅读该书。 图中借阅结束时间是2024-04-23 13:36:29&#xff0c;到期后该书就会从列表中消失。 BookOrderMapper.xml &…

vue3+elementui-plus实现无限递归菜单

效果图 实现方式是&#xff1a;通过给定的数据结构层数来动态生成多级菜单 menu.vue<template><el-menu:default-active"activeIndex"class"el-menu-demo"mode"horizontal"select"handleSelect"background-color"#f8f…

直流负载在新能源领域的作用有哪些

直流负载在新能源领域的作用主要体现在以下几个方面&#xff1a; 新能源如太阳能、风能等&#xff0c;其发电过程中产生的电能为直流电。传统的电力系统主要采用交流电&#xff0c;因此在新能源并网时需要进行逆变器转换。然而&#xff0c;逆变器在转换过程中会存在一定的能量损…