title: 自己手写一个LRU策略

date: 2021-06-18 12:00:30

tags:

- [redis]

- [lru]

categories:

- [redis]

permalink: zxh

prefix: redis

一、题目描述

146. LRU 缓存机制

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。

实现 LRUCache 类:

LRUCache(int capacity) 以正整数作为容量 capacity 初始化LRU缓存

int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。

void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

二、思路分析

第一想法

  • 刚看到本题时没有多想就觉得会用到队列,因为队列FIFO可以做到淘汰末尾数据,但是仔细一想本题是需要淘汰最近最少使用数据,如果仅仅是最近的数据那么队列很容易实现。加上使用频率就涉及到数据的频繁挪动。很明显队列是无法完成的。
  • 那么有没有一种顺序添加的数据,每次在获取之后就会将数据前移至一端呢?答案是有的!LinkedHashMap
  • LinkedHashMap 不熟悉的朋友们可以简单的将它理解成HashMap 。 下图展示了HashMap的存储结构

  • 上述的元素我这里做了个动画演示全过程!!!

  • LinkedHashMap只是多了一条链表串起里面的元素

  • 这也是为什么LinkedHashMap是按照顺序存储的。但是LinkedHahsMap也无法做到按照使用频率进行排序啊?大家都知道他是按照添加顺序排序的!!!

LinkedHashMap改造

  • 原生的LinkedHashMap的确无法满足情况,但是我们稍微看下源码能够发现在put之后都会执行下afterNodeInsertion 这个方法。这也是HashMap留给LinkedHashMap做的扩展!

  • removeNode 就是将最前面的数据。想要进入这个方法就需要removeEldestEntry判断。LinkedHashMap默认是false . 所以我们只需要重写他就行了。但是还是在get值的时候如何保值在最后面呢?我们仔细看下源码就能够发现在get中有这个一个方法afterNodeAccess 。他的作用就是将get的元素移位值后面。正好符合我们LRU的策略特征

  • 综上!我们借助LinkedHashMap就非常容易的实现了LRU策略!

自己实现

  • 但是本题的意思是想考察我们自己是如何实现的,而不是巧妙对现有的工具改造的!不过上面对LinkedHashMap的确改造的很巧这是不可否认的!下面我们就尝试自己来实现下这种方式!

  • 首先我们需要确定需要用到Hash结合链表来实现。Hash我们自然使用HashMap来存储数据为的就是方便定位数据。定位到数据就需要操作链表将数据实时移位值链表尾部,每次淘汰是将链表首位移除既可。为了方便我们操作链表这里的链表肯定是双链表的!

链表单元

  • 首先我们定义一个内部类!用于链表的基本单元。里面存储了key,value方便根据Hash中存储的内容找到节点!preNodenextNode分别指向前后节点

  • 在构建器中初始化容量和链表大小,并初始化边界节点方便我们操作节点中移位和删除。

  • 在获取数据时没有添加就返回-1 , 已经添加的数据则将该数据对应的node节点移动到链表的尾部。

  • 在put中当第一次添加我们需要维护链表大小并进行检测是否需要进行淘汰数据,如果不是第一次添加我们只需奥更新值和对应node在链表中的位置即可

方法名 作用
addToTail 将节点添加值链表尾部
moveToTail 将已经存在于链表中的节点移动到链表的尾部
removeHeadNode 删除链表中第一个节点,注意是边界节点后第一个节点

四、总结

  • 虽然执行时间和内存消耗有点高!但是我就是不优化。
  • 本题主要就是在链表的移动上面会复杂点。我们需要按照添加顺序和使用频率两个维度进行维护他们之间的顺序。只要这个顺序维护好,就没啥问题了!

【redis前传】自己手写一个LRU策略 | redis淘汰策略的更多相关文章

  1. 搞定redis面试--Redis的过期策略?手写一个LRU?

    1 面试题 Redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现? 2 考点分析 1)我往redis里写的数据怎么没了? 我们生产环境的redis怎么经常会丢掉一些数据?写进去了 ...

  2. 手写一个LRU工具类

    LRU概述 LRU算法,即最近最少使用算法.其使用场景非常广泛,像我们日常用的手机的后台应用展示,软件的复制粘贴板等. 本文将基于算法思想手写一个具有LRU算法功能的Java工具类. 结构设计 在插入 ...

  3. 面试题目:手写一个LRU算法实现

    一.常见的内存淘汰算法 FIFO  先进先出 在这种淘汰算法中,先进⼊缓存的会先被淘汰 命中率很低 LRU Least recently used,最近最少使⽤get 根据数据的历史访问记录来进⾏淘汰 ...

  4. 4.redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?

    作者:中华石杉 面试题 redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 面试官心理分析 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当 ...

  5. redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?

    redis的过期策略都有哪些? 设置过期时间: set key 的时候,使用expire time,就是过期时间.指定这个key比如说只能存活一个小时?10分钟?指定缓存到期就会失效. redis的过 ...

  6. 手把手教你手写一个最简单的 Spring Boot Starter

    欢迎关注微信公众号:「Java之言」技术文章持续更新,请持续关注...... 第一时间学习最新技术文章 领取最新技术学习资料视频 最新互联网资讯和面试经验 何为 Starter ? 想必大家都使用过 ...

  7. 只会用就out了,手写一个符合规范的Promise

    Promise是什么 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果.从语法上说,Promise 是一个对象,从它可以获取异步操作的消息.Prom ...

  8. 利用SpringBoot+Logback手写一个简单的链路追踪

    目录 一.实现原理 二.代码实战 三.测试 最近线上排查问题时候,发现请求太多导致日志错综复杂,没办法把用户在一次或多次请求的日志关联在一起,所以就利用SpringBoot+Logback手写了一个简 ...

  9. 手写一个简单的ElasticSearch SQL转换器(一)

    一.前言 之前有个需求,是使ElasticSearch支持使用SQL进行简单查询,较新版本的ES已经支持该特性(不过貌似还是实验性质的?) ,而且git上也有elasticsearch-sql 插件, ...

随机推荐

  1. 一文读懂 SuperEdge 云边隧道

    作者 李腾飞,腾讯容器技术研发工程师,腾讯云TKE后台研发,SuperEdge核心开发成员. 杜杨浩,腾讯云高级工程师,热衷于开源.容器和Kubernetes.目前主要从事镜像仓库,Kubernete ...

  2. svg web拓扑更新了,支持动态添加svg组件

    版本1.0请点此 预览地址 https://svg.yaolunmao.top 如何使用 # 克隆项目 git clone https://github.com/yaolunmao/vue-webto ...

  3. python介绍,计算机核心基础,与运行程序有关的三大核心硬件,操作系统

    python介绍,计算机核心基础,与运行程序有关的三大核心硬件,操作系统 引子 python是什么? 什么是编程语言?为何要有编程语言? 什么是编程?什么是程序?什么是进程?为何要编程? 计算机基础 ...

  4. CAS的理解

    CAS(CompareAndSweep)工作方式 ​ CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被 ...

  5. 记一次golang内存泄露

    记一次golang内存泄露 最近在QA环境上验证功能时,发现机器特别卡,查看系统内存,发现可用(available)内存仅剩200多M,通过对进程耗用内存进行排序,发现有一个名为application ...

  6. hive beeline详解

    Hive客户端工具后续将使用Beeline 替代HiveCLI ,并且后续版本也会废弃掉HiveCLI 客户端工具,Beeline是 Hive 0.11版本引入的新命令行客户端工具,它是基于SQLLi ...

  7. 在linux下把jsp文件 打包war格式(centos7)

    在linux下把jsp文件 打成war包 chmod -R 777 /data/jdk8u242-b08/bincd /data/TongWeb61712/deployment/TestCase//d ...

  8. 059.Python前端Django组件cooki和session

    一 会话跟踪技术 1.1 什么是会话 会话是指一个终端用户(服务器)与交互系统(客户端)进行通讯的过程. 1.2 什么是会话跟踪 对同一个用户对服务器的连续的请求和接受响应的监视.(将用户与同一用户发 ...

  9. Linux Access.conf安全配置

    access.conf is the configuration file used to logins to the Linux or Unix systems. This file is loca ...

  10. Linux shell用sed批量更改文件名的相关内容

    示例 去除特定字符 目标:将指定目录下文件名中sprint替换为dev 方法: [root@Skip-ftp test]# for i in `ls` > do > name=`echo ...