返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JavaScript实现LRU算法的示例详解
  • 280
分享到

JavaScript实现LRU算法的示例详解

JavaScript实现LRU算法JavaScriptLRU算法JavaScriptLRU 2023-05-17 20:05:31 280人浏览 独家记忆
摘要

目录LRU简介如何实现实现思路缺陷双向链表+哈希表双向链表实现思路不知道屏幕前的朋友们,有没有和我一样,觉得LRU算法原理很容易理解,实现起来却很复杂。 明明一个map就能解决,标准

不知道屏幕前的朋友们,有没有和我一样,觉得LRU算法原理很容易理解,实现起来却很复杂。

明明一个map就能解决,标准答案却总要使用双向链表。

实现思路很很容易理解,但是下笔写代码总是磕磕绊绊。

但是这个算法在前端使用场景很多,面试经常问,正巧我遇到了这个问题,因此抓住机会和大家记录分享一下

LRU简介

least Recently Used 最近最少使用,用于操作系统内存管理,在前端开发中常用于优化页面性能和资源利用率。

直接翻译就是“最不经常使用的数据,重要性是最低的,应该优先删除”

以下是在前端中使用LRU算法的几个应用场景:

前端路由:在单页应用(SPA)中,通过将路由信息保存在缓存中,可以避免每次访问页面时都需要重新加载数据,从而提高页面响应速度和用户体验。

图片懒加载:对于大型图片库,可以使用LRU算法对已加载的图片进行缓存,当一个新图片需要被加载时,可以先检查该图片是否已经在缓存中存在,如果存在则直接从缓存中获取,否则从服务器加载。

数据缓存:对于需要频繁读取的数据或者需要复杂计算才能得出结果的数据,可以使用LRU算法对其进行缓存,以减少重复计算的时间。

字体应用:对于网站上使用的字体文件,可以使用LRU算法将最常用的字体文件存储在缓存中,从而加快页面渲染速度和节省网络流量。

总之,LRU算法可用于提升前端应用的性能和用户体验,但需要根据具体的应用场景选择合适的算法并进行合理的配置。

如何实现

那么如何实现一个LRU 算法呢?我们一起看看LeetCode 146这道题目

设计一个LRU类,实现get put 方法

题目简单描述:

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构

实现 LRUCache 类:

  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

实现思路

我们使用一个map 来缓存数据。

当获取数据key 时,优先判断是否存在于map,如果在我们先拿到这个值存为temp,然后从map中删除,重新set进map中

当插入数据时,优先判断是否存在于map,如果不存在,直接set,如果存在,删除后哦吗,重新set

这样我们保证最近使用的都在map 的最下层,当内存超出时,直接删除map 顶层元素即可

this.map.delete(this.map.keys().next().value)

var LRUCache = function(capacity) {
	this.capacity = capacity
  this.map = new Map()
}

LRUCache.prototype.get = function(key) {
  if(this.map.has(key)) {
    let temp = this.map.get(key)
    this.map.delete(key)
    this.map.set(key,temp)
    return temp
  } else {
    return -1
  }

}
LRUCache.prototype.put = function(key, value) {
	if(this.map.has(key)) {
    this.map.delete(key)
  }
  this.map.set(key,value)
  if(this.map.size > this.capacity) {
    this.map.delete(this.map.keys().next().value)
  }
}

缺陷

虽然该实现使用了 Map 对象,但是在最坏情况下,如果哈希函数分布不均匀,可能会导致哈希冲突,使得某些操作的时间复杂度变为 O(n)。因此,在实际应用中,如果需要高效地处理大规模数据,建议使用双向链表或其他更高效的数据结构。

假设有一个哈希表,大小为 5,使用的哈希函数为 key % 5。现在插入以下 6 个键值对:

{key: 1, value: 'a'}
{key: 2, value: 'b'}
{key: 3, value: 'c'}
{key: 4, value: 'd'}
{key: 6, value: 'e'}
{key: 11, value: 'f'}

根据给定的哈希函数 key % 5,可以将每个键映射到哈希表中的一个桶。具体来说,将键除以 5 并取余数,以得到它应该插入的桶的索引

使用这个哈希函数,将上述六个键值对插入哈希表中,得到以下结果:

在索引 1 的桶中插入 {key: 1, value: 'a'}

在索引 2 的桶中插入 {key: 2, value: 'b'}

'在索引 3 的桶中插入 {key: 3, value: 'c'}

在索引 4 的桶中插入 {key: 4, value: 'd'}

在索引 1 的桶中插入 {key: 6, value: 'e'}

在索引 1 的桶中插入 {key: 11, value: 'f'}

注意,在将键为 6 和 11 的键值对插入哈希表时,它们都被映射到索引 1 的桶中。这是因为它们分别与 1 余数相同。

当出现哈希冲突时,即多个键被映射到同一桶时

这种情况下,在操作时需要遍历整个桶来查找指定的键值对,因此操作的时间复杂度变为 O(n)。

双向链表+哈希表

那么如何达到O(1)的时间复杂度呢?

那肯定选用 map 查询。修改,删除也要尽量 O(1) 完成。搜寻常见的数据结构,链表,栈,队列,树,图。树和图排除,栈和队列无法任意查询中间的元素,也排除。所以选用链表来实现。但是如果选用单链表,删除这个结点,需要 O(n) 遍历一遍找到前驱结点。所以选用双向链表,在删除的时候也能 O(1) 完成。

核心就是:最近最多使用的节点永远在链表结尾,最近最少使用的节点在链表开头。

双向链表

双向链表的结构

value: 存储的值

prev: 指向前一个元素的指针

next: 指向下一个元素的指针

Head和Tail是虚拟的头部和尾部节点,这是为了方便找到链表的首末设定的

       ┌──────>┐    ┌───────>┐   ┌───────>┐
  head • (x|"three"|•)  (•|"two"|•)  (•|"one"|x) • tail
               └<────────┘   └<───────┘   └<─────┘

实现思路

1.使用一个Map 对象来存储键值对

2.使用一个双向链表维护键值对的顺序

3.抽离出一个addToTaill 方法(将节点插入末尾)抽离出一个remove 方法(删除节点)

4.当执行put 操作时,判断节点是否在map中

  • 如果存在,获取当前节点值,在双向链表中remove删除改节点,重新调用 addToTail 添加到末尾
  • 如果不存在,建立一个双向链表节点,调用 addToTail 添加到末尾,同时添加进map
  • 如果超过容量this.size > this.cap,删除当前head节点,从map中删除当前key

5.当执行get 操作时,判断节点是否在map中

  • 如果不存在,返回-1
  • 如果存在,获取当前key,value,重新执行put 操作
class Listnode {
  constructor(key, value) {
    this.key = key;
    this.val = value;
    this.prev = null;
    this.next = null;
  }
}

class LRUCache {
  constructor(capacity = 10) {
    this.capacity = capacity;
    // 实际保存的键值对数量
    this.size = 0;
    this.map = {};
    //代表最旧的节点
    this.head = null;
    //代表最新的节点
    this.tail = null;
  }

  get(key) {
    const node = this.map.get(key);
    if (!node) return -1;
    let node = this.map[key];
    this.put(node.key, node.val);
    return node.value;
  }

  put(key, value) {
    if(this.map[key]) {
    	let node = this.map[key]
      node.val = value
      this.remove(node)
      this.addTotail(node)
    } else {
      let node = new ListNode(key,value)
      this.addTotail(node)
      this.map[key] = node
      this.size++
    }
    if (this.size > this.cap) {
      let key = this.head.key;
      this.remove(this.head);
      delete this.map[key];
      this.size--;
    }
  }
  addToTail(node) {
    if(this.tail) {
      this.tail.next = node
      node.prev = this.tail
      this.tail = node
    } else {
      this.tail = node
      this.head = node
    }
  }
  remove(node) {
    if(node.prev) {
      node.prev.next = node.next
    } else {
      this.head = this.head.next
    }
    if(node.next) {
      node.next.prev = node.prev
    } else {
      this.tail = this.tail.prev
    }
    node.prev = node.next = null;
  }
}

以上就是javascript实现LRU算法的示例详解的详细内容,更多关于JavaScript LRU算法的资料请关注编程网其它相关文章!

--结束END--

本文标题: JavaScript实现LRU算法的示例详解

本文链接: https://lsjlt.com/news/211503.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JavaScript实现LRU算法的示例详解
    目录LRU简介如何实现实现思路缺陷双向链表+哈希表双向链表实现思路不知道屏幕前的朋友们,有没有和我一样,觉得LRU算法原理很容易理解,实现起来却很复杂。 明明一个map就能解决,标准...
    99+
    2023-05-17
    JavaScript实现LRU算法 JavaScript LRU算法 JavaScript LRU
  • PHP实现LRU算法的示例代码
    本篇文章主要给大家介绍了PHP的相关知识,LRU是Least Recently Used 近期最少使用算法, 内存管理的一种页面置换算法,下面将详解LRU算法的原理以及实现,下面一起来看一下,希望对大家有帮助。(推荐教程:PHP视频教程)原...
    99+
    2022-08-08
    php
  • JavaScript手写LRU算法的示例代码
    目录一、基本要求二、数据结构2.1 Map2.2 Doubly Linked List三、Map 实现四、双向链表实现4.1 定义节点类4.2 定义链表类4.3 定义 LRU 类4....
    99+
    2024-04-02
  • JavaScript双向链表实现LRU缓存算法的示例代码
    目录目标什么是LRU简介硬件支持寄存器栈代码实现思路链表节点数据结构链表数据结构LRUCache数据结构完整代码测试目标 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束...
    99+
    2024-04-02
  • PHP实现LRU算法的原理详解
    1.概念 LRU : 最近最少使用算法 2.代码 <php class Node { public $preKey = null; //链表前一个节点 publ...
    99+
    2024-04-02
  • LRU LFU TinyLFU缓存算法实例详解
    目录简介一、LRU和LFU算法LRU算法LFU算法小结:二、TinyLFU三、Window-TinyLFU简介 前置知识 知道什么是缓存 听完本节公开课,你可以收获 掌握朴素LRU、...
    99+
    2024-04-02
  • Java实现LRU缓存算法的参考示例
    目录一、什么是 LRU二、Java 实现 LRU 缓存算法一、什么是 LRU LRU(Least Recently Used,最近最少使用)是...
    99+
    2023-05-20
    Java 算法 Java LRU缓存算法 Java LUR
  • JavaScript实现基础排序算法的示例详解
    目录前言正文1、冒泡排序2、选择排序3、插入排序4、快速排序前言 文本来总结常见的排序算法,通过 JvavScript  来实现 正文 1、冒泡排序 算法思想:比较相邻两个...
    99+
    2024-04-02
  • Java实现LRU缓存的实例详解
    Java实现LRU缓存的实例详解1.CacheCache对于代码系统的加速与优化具有极大的作用,对于码农来说是一个很熟悉的概念。可以说,你在内存中new 了一个一段空间(比方说数组,list)存放一些冗余的结果数据,并利用这些数据完成了以空...
    99+
    2023-05-31
    java lru缓存 ava
  • Python实现LRU算法
    在第一节中已经实现了双向链表DoubleLinkedList类,本节我们基于双向链表实现LRU(Least Recently Used最近最少使用)缓存置换算法。Redis的淘汰机制...
    99+
    2024-04-02
  • LRU算法——python实现
    在LeetCode上看到这么一道题: Design and implement a data structure for Least Recently Used (LRU) cache. It should support the f...
    99+
    2023-01-31
    算法 LRU python
  • 手动实现Redis的LRU缓存机制示例详解
    前言 最近在逛博客的时候看到了有关Redis方面的面试题,其中提到了Redis在内存达到最大限制的时候会使用LRU等淘汰机制,然后找了这方面的一些资料与大家分享一下。 LRU总体大概...
    99+
    2024-04-02
  • JavaScript如何实现LRU缓存淘汰算法
    目录如何实现LRU缓存淘汰算法使用哈希表和双向链表哈希表实现LRU缓存淘汰算法如何实现LRU缓存淘汰算法 LRU(Least Recently Used)缓存淘汰算法是一种常见的缓存...
    99+
    2023-05-17
    JavaScript LRU缓存淘汰算法 LRU缓存淘汰算法 JavaScript LRU
  • Nodejs基于LRU算法实现的缓存处理操作示例
    本文实例讲述了Nodejs基于LRU算法实现的缓存处理操作。分享给大家供大家参考,具体如下: LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,是...
    99+
    2022-06-04
    示例 缓存 算法
  • Matlab实现遗传算法的示例详解
    目录1算法讲解1.1何为遗传算法1.2遗传算法流程描述1.3关于为什么要用二进制码表示个体信息1.4目标函数值与适应值区别1.5关于如何将二进制码转化为变量数值1.6关于代码改进2M...
    99+
    2024-04-02
  • C++实现贪心算法的示例详解
    目录区间问题区间选点最大不相交区间数量区间分组区间覆盖Huffman树合并果子排序不等式排队打水绝对值不等式货舱选址区间问题 区间选点 给定 N 个闭区间 [ai,bi],请你在数轴...
    99+
    2024-04-02
  • java LRU算法介绍与用法示例
    本文实例讲述了java LRU算法介绍与用法。分享给大家供大家参考,具体如下:1.前言在用户使用联网的软件的时候,总会从网络上获取数据,当在一段时间内要多次使用同一个数据的时候,用户不可能每次用的时候都去联网进行请求,既浪费时间又浪费网络这...
    99+
    2023-05-31
    java lru 算法
  • JavaScript实现LRU缓存的三种方式详解
    目录分析使用Map实现LRU缓存使用Object + Array实现LRU缓存使用双向链表实现LRU总结LRU全称为Least Recently Used,即最近使用的。针对的是在有...
    99+
    2024-04-02
  • LRU算法及Apache LRUMap源码实例解析
    目录1. 什么是LRU1.1 自定义实现LRU的要求1.2 Apache LRUMap示例1.2.1 pom依赖1.2.2 demo2. 源码解析2.1 设计2.2 数据结构2.3 ...
    99+
    2024-04-02
  • PHP如何实现LRU算法
    小编给大家分享一下PHP如何实现LRU算法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!整体设计用数组保存缓存对象(Node);缓存对象(Node)之间通过nex...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作