当前位置: 首页 > 编程日记 > 正文

漫画:什么是LRU算法?

本期封面作者:A17

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg



—————  两个月前  —————



640?wx_fmt=jpeg

640?wx_fmt=jpeg



640?wx_fmt=jpeg



640?wx_fmt=png



640?wx_fmt=jpeg

640?wx_fmt=jpeg

用户信息当然是存在数据库里。但是由于我们对用户系统的性能要求比较高,显然不能每一次请求都去查询数据库。

所以,小灰在内存中创建了一个哈希表作为缓存,每次查找一个用户的时候先在哈希表中查询,以此提高访问性能。

640?wx_fmt=png



很快,用户系统上线了,小灰美美地休息了几天。

一个多月之后......

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg



640?wx_fmt=jpeg



———————————————

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg

640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg



什么是哈希链表呢?

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

640?wx_fmt=png

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

640?wx_fmt=png

这样一来,原本无序的哈希表拥有了固定的排列顺序。

640?wx_fmt=jpeg


640?wx_fmt=jpeg

让我们以用户信息的需求为例,来演示一下LRU算法的基本思路:

1.假设我们使用哈希链表来缓存用户信息,目前缓存了4个用户,这4个用户是按照时间顺序依次从链表右端插入的。

640?wx_fmt=png

2.此时,业务方访问用户5,由于哈希链表中没有用户5的数据,我们从数据库中读取出来,插入到缓存当中。这时候,链表中最右端是最新访问到的用户5,最左端是最近最少访问的用户1。

640?wx_fmt=png

3.接下来,业务方访问用户2,哈希链表中存在用户2的数据,我们怎么做呢?我们把用户2从它的前驱节点和后继节点之间移除,重新插入到链表最右端。这时候,链表中最右端变成了最新访问到的用户2,最左端仍然是最近最少访问的用户1。

640?wx_fmt=png


640?wx_fmt=png

4.接下来,业务方请求修改用户4的信息。同样道理,我们把用户4从原来的位置移动到链表最右侧,并把用户信息的值更新。这时候,链表中最右端是最新访问到的用户4,最左端仍然是最近最少访问的用户1。

640?wx_fmt=png

640?wx_fmt=png

5.后来业务方换口味了,访问用户6,用户6在缓存里没有,需要插入到哈希链表。假设这时候缓存容量已经达到上限,必须先删除最近最少访问的数据,那么位于哈希链表最左端的用户1就会被删除掉,然后再把用户6插入到最右端。

640?wx_fmt=png

640?wx_fmt=png

以上,就是LRU算法的基本思路。

640?wx_fmt=jpeg


640?wx_fmt=jpeg

  1. private Node head;

  2. private Node end;

  3. //缓存存储上限

  4. private int limit;




  5. private HashMap<String, Node> hashMap;




  6. public LRUCache(int limit) {

  7.    this.limit = limit;

  8.    hashMap = new HashMap<String, Node>();

  9. }




  10. public String get(String key) {

  11.    Node node = hashMap.get(key);

  12.    if (node == null){

  13.        return null;

  14.    }

  15.    refreshNode(node);

  16.    return node.value;

  17. }




  18. public void put(String key, String value) {

  19.    Node node = hashMap.get(key);

  20.    if (node == null) {

  21.        //如果key不存在,插入key-value

  22.        if (hashMap.size() >= limit) {

  23.            String oldKey = removeNode(head);

  24.            hashMap.remove(oldKey);

  25.        }

  26.        node = new Node(key, value);

  27.        addNode(node);

  28.        hashMap.put(key, node);

  29.    }else {

  30.        //如果key存在,刷新key-value

  31.        node.value = value;

  32.        refreshNode(node);

  33.    }

  34. }




  35. public void remove(String key) {

  36.    Node node = hashMap.get(key);

  37.    removeNode(node);

  38.    hashMap.remove(key);

  39. }




  40. /**

  41. * 刷新被访问的节点位置

  42. * @param  node 被访问的节点

  43. */

  44. private void refreshNode(Node node) {

  45.    //如果访问的是尾节点,无需移动节点

  46.    if (node == end) {

  47.        return;

  48.    }

  49.    //移除节点

  50.    removeNode(node);

  51.    //重新插入节点

  52.    addNode(node);

  53. }




  54. /**

  55. * 删除节点

  56. * @param  node 要删除的节点

  57. */

  58. private String removeNode(Node node) {

  59.    if (node == end) {

  60.        //移除尾节点

  61.        end = end.pre;

  62.    }else if(node == head){

  63.        //移除头节点

  64.        head = head.next;

  65.    } else {

  66.        //移除中间节点

  67.        node.pre.next = node.next;

  68.        node.next.pre = node.pre;

  69.    }

  70.    return node.key;

  71. }




  72. /**

  73. * 尾部插入节点

  74. * @param  node 要插入的节点

  75. */

  76. private void addNode(Node node) {

  77.    if(end != null) {

  78.        end.next = node;

  79.        node.pre = end;

  80.        node.next = null;

  81.    }

  82.    end = node;

  83.    if(head == null){

  84.        head = node;

  85.    }

  86. }




  87. class Node {

  88.    Node(String key, String value){

  89.        this.key = key;

  90.        this.value = value;

  91.    }

  92.    public Node pre;

  93.    public Node next;

  94.    public String key;

  95.    public String value;

  96. }




  97. public static void main(String[] args) {

  98.    LRUCache lruCache = new LRUCache(5);

  99.    lruCache.put("001", "用户1信息");

  100.    lruCache.put("002", "用户1信息");

  101.    lruCache.put("003", "用户1信息");

  102.    lruCache.put("004", "用户1信息");

  103.    lruCache.put("005", "用户1信息");

  104.    lruCache.get("002");

  105.    lruCache.put("004", "用户2信息更新");

  106.    lruCache.put("006", "用户6信息");

  107.    System.out.println(lruCache.get("001"));

  108.    System.out.println(lruCache.get("006"));

  109. }


需要注意的是,这段不是线程安全的,要想做到线程安全,需要加上synchronized修饰符。

640?wx_fmt=jpeg


640?wx_fmt=jpeg


640?wx_fmt=jpeg

640?wx_fmt=jpeg

告诉大家一个好消息,小灰的《漫画算法》全面上架啦,在短短的两周里,本书一度霸占着各大畅销榜榜首!

640?wx_fmt=png

扫码或者点击封面查看详情

640?wx_fmt=png

小灰把两年多以来积累的漫画作品进行了筛选和优化,并加上了一些更为基础和系统的入门章节,最终完成了本书的六大篇章:


第一章 算法概述

介绍了算法和数据结构的相关概念,告诉大家算法是什么,数据结构又是什么,它们有哪些用途,如何分析时间复杂度,如何分析空间复杂度。

第二章 数据结构基础

介绍了最基本的数据结构,包括数组、链表、栈、队列、哈希表的概念和读写操作。

第三章 树

介绍了树和二叉树的概念、二叉树的各种遍历方式、二叉堆和优先队列的应用。

第四章 排序算法

介绍了几种典型的排序算法,包括冒泡排序、快速排序、堆排序、计数排序、桶排序。

第五章 面试中的算法

介绍了10余道职场上流行的算法面试题及详细的解题思路。例如怎样判断链表有环、怎样计算大整数相加等。

第六章 算法的实际应用

介绍了算法在职场上的一些应用,例如使用LRU算法来淘汰冷数据,使用Bitmap算法来统计用户特征等。

本书是全彩印制,书中的每一章、每一节、每一句话、每一幅图、每一行代码,都经过了小灰和编辑们的精心打磨,力求用最为直白的方式把知识讲明白、讲透彻。

640?wx_fmt=png


640?wx_fmt=png

早期的漫画中存在一些叙述错误和表达不清晰的地方,小灰在本书中做了修正和补充;同时书中增加了许多全新的篇章,使得本书的内容更加系统和全面。

对于渴望学习算法的小伙伴,无论你是正在学习计算机专业的学生,还是已经进入职场的新人,亦或是拥有多年工作经验却不擅长算法的老手,这本《漫画算法》都能帮助你告别对算法的恐惧,认识算法、掌握算法。

扫码或点击阅读原文购买

新品8折优惠中

640?wx_fmt=png


相关文章:

第15章节-Python3.5-Django实现用户登录与前端交互2 14

目的我想登陆成功后显示我的后台管理(实现过程): 新建home.html 在templates目录下代码如下: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body style"…

【GLib】GLib学习笔记(一):GLib、GObject、GType

1、GLib GLib是 Gtk 库和 Gnome 的基础。glib 可以在多个平台下使用&#xff0c;比如 Linux、Unix、Windows 等。GLib为许多标准的、常用的 C 语言结构提供了相应的替代物。 GLib是GTK的基础库&#xff0c;它由基础类型、对核心应用的支持、实用功能、数据类型和对象系统五个…

tomcat配置tomcat-redis-session-manager

为什么80%的码农都做不了架构师&#xff1f;>>> 今天写了半天程序&#xff0c;有点乏了。想想来配置一下tomcat-redis-session-manager吧&#xff0c;但是按照 官方文档配了总是tomcat启动错误。 java.lang.NoClassDefFoundError: org/apache/commons/pool/impl/Ge…

链式比较、奇怪的字母、有趣的import...Python冷知识(六)

本文转载自Python编程时光&#xff08;ID:Python-Time&#xff09;冷知识系列&#xff0c;已经更新至第六篇。谈谈 Python 那些不为人知的冷知识&#xff08;一&#xff09;谈谈 Python 那些不为人知的冷知识&#xff08;二&#xff09;谈谈 Python 那些不为人知的冷知识&#…

【GLib】GLib学习笔记(二):源码编译

一、源码下载 http://ftp.acc.umu.se/pub/GNOME/sources/glib/本人下载是最新版本(截至2020-08-26)&#xff1a;glib-2.65.2.tar.xz 二、安装依赖 1、安装依赖库 sudo apt install cmake sudo apt install zlib1g-dev sudo apt install meson sudo apt install ninja sudo …

java之类和对象

概述 面向过程&#xff1a;面向过程主要是把问题分解成多个不同的步骤&#xff0c;然后把各个步骤变成方法&#xff0c;它更强调过程。代表语言&#xff1a;c 面向对象&#xff1a;面向对象会把问题分解成各个对象&#xff0c;然后各个对象之间进行交互&#xff0c;每个对象内部…

【GLib】GLib学习笔记(三):gtypes、garray、gerror、goption

1、类型&#xff1a;glib/gtypes.h 1.1 基本类型&#xff1b; typedef char gchar; typedef short gshort; typedef long glong; typedef int gint; typedef gint gboolean;typedef unsigned char guchar; typedef unsigned short gushort; typedef unsigned lo…

Bert时代的创新:Bert应用模式比较及其它 | 技术头条

作者&#xff1a;张俊林&#xff0c;中国中文信息学会理事&#xff0c;中科院软件所博士。目前在新浪微博 AI Lab 担任资深算法专家。在此之前&#xff0c;张俊林曾经在阿里巴巴任资深技术专家并负责新技术团队&#xff0c;以及在百度和用友担任技术经理及技术总监等职务。他是…

HashSet 详解

为什么80%的码农都做不了架构师&#xff1f;>>> package com.sun;/* |——SortedSet接口——TreeSet实现类 Set接口——|——HashSet实现类|——LinkedHashSet实现类 HashSet 此类实现 Set 接口&#xff0c;由哈希表&#xff08;实际上是一个 HashMap 实例&#…

肖仰华:知识图谱落地,不止于“实现”

作者 | Just出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;“知识将比数据更重要&#xff0c;得知识者得天下”&#xff0c;去年十月&#xff0c;在 CSDN 对肖仰华教授的一篇约稿里&#xff0c;他指出数据的真正价值蕴含于其深加工的知识中。从 Google 于 2012 年提…

【摄像头】摄像头相关名词解释

1、白平衡 白平衡,字面上的理解是白色的平衡。白平衡是描述显示器中红、绿、蓝三基色混合生成后白色精确度的一项指标。 那什么是白色?这就涉及到一些色彩学的知识,白色是指反射到人眼中的光线由于蓝、绿、红三种色光比例相同且具有一定的亮度所形成的视觉反应。我们都知道…

金额跳动动画效果

前言 金额效果&#xff0c;因为觉得公司目前的金额太乏味&#xff0c;决定加点效果&#xff0c;也特此写了个小demo&#xff0c;代码非常简单&#xff0c;贴代码方便大家看看 通过 runtime 建立属性(setter/getter方法) /** 由于分类中要添加属性&#xff0c;所以通过runtime方…

POJ 3070 Fibonacci

裸奔的矩阵乘法&#xff0c;当模板了。 #include <iostream>#include <cstring>#include <cstdio>using namespace std;const int N 2;const int MOD 10000;struct Mat {long long mat[N][N];void init() {for(int i 0; i < N; i) {for(int j 0; j &l…

推荐一个小而美的Python代码格式化工具

代码可读性是评判代码质量的标准之一&#xff0c;有一个衡量代码质量的标准是 Martin 提出的 “WFT” 定律&#xff0c;即每分钟爆出 “WTF” 的次数。你在读别人代码或者做 Code Review 的时候有没有 “WTF” 冲动呢&#xff1f; 为了帮助开发者统一代码风格&#xff0c;Pytho…

【摄像头】摄像机工作原理

1、摄像机工作原理 外部光线穿过镜头(lens)后&#xff0c; 经过滤光片(color filter)滤波后照射到光学传感器(Sensor)上面&#xff0c; Sensor 将从 lens 上传导过来的光线转换为电信号&#xff0c;再通过内部的 AD 转换为数字信号。 如果 Sensor 没有集成 DSP&#xff0c;则通…

@程序员,别再自己闷头学了

60 年冬去春来&#xff0c;人工智能技术发展起起落落。现在是 2019 年&#xff0c;属于 AI 不可阻挡的新转机正强势袭来。 科技巨头一向是未来技术发展最重要的风向标。2011 年&#xff0c;随着 Google 将一线业务引入深度学习技术&#xff0c;落伍移动时代的微软也拉起了一支…

linux下的oracle10g rman备份

RMAN是Oracle提供的一个数据库备份和恢复工具&#xff0c;利用rman可以比较方便的对数据库进行备份。Oracle 数据库可运行在归档和非归档模式下&#xff0c;这两者的区别就在于对redo log的处理。归档模式下&#xff0c;当一个redo log 写满之后&#xff0c;就会把这个redo lo…

最全Python算法实现资源汇总!

整理 | Rachel责编 | Jane出品 | Python大本营&#xff08;ID&#xff1a;pythonnews&#xff09;【导语】数据结构与算法是所有人都要学习的基础课程&#xff0c;自己写算法的过程可以帮助我们更好地理解算法思路&#xff0c;不要轻视每一个算法&#xff0c;一些虽然看似容易&…

【摄像头】低照度和光圈

1、低照度 低照度摄像机是指在较低光照度的条件下仍然可以摄取清晰图像的摄像头。 照度,即光照强度,是一种物理术语,指单位面积上所接受可见光的能量。单位:勒克斯Lux,简作Lx。 照度和光圈大小的关系:镜头的光圈越大(F值越小),所需的照度越低。这个好理解,光圈大了进…

CART树 python小样例

决策树不断将数据切分成小数据集&#xff0c;直到所有目标变量完全相同&#xff0c;或者数据不能再切分为止&#xff0c;决策时是一种贪心算法&#xff0c;它要在给定的时间内做出最佳选择&#xff0c;但并不关心能否达到最优 树回归 优点&#xff1a;可以对复杂和非线性的数据…

Directx教程(24) 简单的光照模型(3)

在工程myTutorialD3D11_17中&#xff0c;我们重新定义我们的cube顶点法向&#xff0c;每个三角形面的顶点法向都是和这个三角形的面法向是一致的。如下图所示&#xff1a; 在该工程中&#xff0c;我们还修改了CubeModelClass文件&#xff0c;从一个cube.txt文件中读cube顶点位置…

SSM框架之批量增加示例(同步请求jsp视图解析)

准备环境:SSM框架JDK8/JDK7MySQL5.7MAVEN3以上Tomcat8/7应用服务器 示例说明: 分发给用户优惠券&#xff0c;通过checkbox选中批量分发&#xff0c;对应也就是批量增加。 对于公司使用freemarket或者jsp或者volocity&#xff0c;有一定的启示意思。 不论视图用的是jsp或者非jsp…

四大指标超现有模型!少样本的无监督图像翻译效果逆天| 技术头条

作者 | Ming-yu Liu, Xun Huang, Arun Mallya, Tero Karras, Timo Aila, Jaakko Lehtinen译者 | linstancy编辑 | Rachel出品 | AI 科技大本营&#xff08;ID:rgznai100&#xff09;【导读】在已有的图像翻译研究中&#xff0c;模型需要使用大量的多类别图像数据&#xff0c;在…

【摄像头】镜头焦距

【摄像头】低照度和光圈 1、简介 在镜头上有两个非常重要的参数,一个是光圈、一个是焦距。 如果在镜头上只标注有一个数字的就是定焦头,比如:50mm,就表示这是一只焦距为50mm的定焦头。 如果在镜头上标注有两个数字的就是变焦头,比如:18-55mm,就表示这只镜头焦距覆盖…

(转)C语言字节对齐

图片可以在下面的博客中看到. 转自:http://blog.csdn.net/bigloomy/article/details/6633008 可能有不少读者会问&#xff0c;字节对齐有必要拿出来单独写一篇博客嘛&#xff1f;我觉得是很有必要&#xff0c;但是它却是被很多人所忽视的一个重点。那么我们使用字节对齐的作用…

赌5毛钱,你解不出这道Google面试题

作者 | Kevin Ghadyani 译者 | 清儿爸 编辑 | Rachel 出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 为了更了解其他人对软件工程的看法&#xff0c;我开始疯狂在 YouTube 上追 TechLead 的视频。在接下来的几天里&#xff0c;我为他在 Google 工作时…

【摄像头】摄像头IRCUT滤光片

1、IRCUT组成原理 IRCUT由两层滤光片组成&#xff0c;一片红外截止或吸收滤光片和一片全透光谱滤光片。 白天是红外截止滤光片工作&#xff0c;晚上是全透滤光片工作&#xff1a; 白天摄像头可以接收到人眼无法识别的红外线&#xff0c;会导致图像与肉眼所见有偏差&#xff0c…

修改Java-source版本

2019独角兽企业重金招聘Python工程师标准>>> pom.xml添加以下&#xff1a;<plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin>&l…

HDU 2519 新生晚会【求组合数】

Problem Description开学了&#xff0c;杭电又迎来了好多新生。ACMer想为新生准备一个节目。来报名要表演节目的人很多&#xff0c;多达N个&#xff0c;但是只需要从这N个人中选M个就够了&#xff0c;一共有多少种选择方法&#xff1f;Input数据的第一行包括一个正整数T&#x…

【摄像头】宽动态范围

1、什么是动态范围 简单的来说,就是摄像机拍摄的同一个画面内,能正常显示细节的最亮和最暗物体的亮度值所包含的那个区间。动态范围越大,过亮或过暗的物体在同一个画面中都能正常显示的程度也就越大。 根据百度百科,当在强光源(日光、灯具或反光等)照射下的高亮度区域及…