问题:
请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity)以 正整数 作为容量capacity初始化 LRU 缓存int get(int key)如果关键字key存在于缓存中,则返回关键字的值,否则返回-1。void put(int key, int value)如果关键字key已经存在,则变更其数据值value;如果不存在,则向缓存中插入该组key-value。如果插入操作导致关键字数量超过capacity,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
思路: 通过使用哈希表和双向链表实现一个满足LRU缓存约束的数据结构。
首先,你可以设计一个节点类来表示双向链表的节点,该节点包含key和value,并且具有指向前一个节点和后一个节点的指针。然后,你可以使用哈希表来存储key和对应节点的映射关系。
每当get或put操作发生时,你都需要将被访问的节点移动到双向链表的头部,表示最近被使用过。如果容量已满,在插入新节点之前,你需要从双向链表的尾部删除最久未使用的节点,并且在哈希表中也删除对应的映射关系。
运行代码:
// LRU 用到的结点
// Hash key=> value
// 链表 结点
// Hash链表
class ListNode {
constructor(key, val) {
this.key = key; //? O(1) key->
this.val = val; // val
this.pre = null; // pre
this.next = null; // next
}
}
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.size = 0;
this.data = {} ; // hashMap Map O(1)
this.head = new ListNode();
this.tail = new ListNode();
this.head.next = this.tail;
this.tail.pre = this.head;
}
put(key, val) {
if (!this.data[key]) {
// new
let node = new ListNode(key, val);
this.data[key] = node;
// head 指针指向的是
this.appendHead(node); //
this.size++;
if (this.size > this.capacity) {
const lastKey= this.removeTail()
delete this.data[lastKey]
this.size--
}
} else {
// update
let node = this.data[key];
this.removeNode(node);
node.val = val;
this.appendHead(node);
}
}
get(key) {
if (!this.data[key]) return -1;
else {
let node = this.data[key];
this.removeNode(node);
this.appendHead(node);
return node.val;
}
}
appendHead(node) {
let firstNode = this.head.next;
this.head.next = node;
node.pre = this.head;
node.next = firstNode;
firstNode.pre = node;
}
removeTail() {
let key = this.tail.pre.key;
this.removeNode(this.tail.pre)
return key;
}
removeNode(node) {
let preNode = node.pre;
let nextNode = node.next;
preNode.next = nextNode;
nextNode.pre = preNode
}
}
LRU作用以及应用场景:
-
LRU(Least Recently Used,最近最少使用)是一种缓存淘汰算法,它的核心思想是当缓存容量达到上限时,淘汰最久未使用的数据,以腾出空间来存储新的数据。该算法的目标是尽可能地保留那些被访问频率较高的数据,同时能够自动淘汰最久未使用的数据,以提高缓存的命中率。 上面代码可以在 O(1) 的时间复杂度内完成插入、查询和删除等操作,同时能够自动淘汰最久未使用的数据,适用于存储较小数据量但访问频率高的场景,如 Web 应用程序中的资源缓存、数据库查询结果缓存等。
-
例如,当用户访问一个 Web 页面时,浏览器会将页面的资源(如图片、样式表、脚本等)缓存到本地,以提高页面加载速度。如果使用 LRU Cache 来管理这些缓存,可以有效地减少网络请求次数,提高用户体验。另外,数据库查询结果缓存也是常见的应用场景,通过将查询结果缓存到内存中,可以减少数据库查询的次数,提高系统响应速度。
总结: LRU - 蓦然回首,缓存已不复返!
在现代科技的浪潮中,缓存是提高系统性能的利器。而其中最受瞩目的就是 LRU Cache,这位于缓存江湖之巅的璀璨明星。
本文带你探索 LRU 的奥秘,就像解锁一个神秘宝盒。首先,让我们揭开它的面纱:LRU(Least Recently Used)算法,即最近最少使用算法。它以独特的方式管理数据,将最近被使用的数据保留在内存中,而最久未使用的数据则被无情地淘汰,为新数据腾出空间。
那么,LRU 又是如何运作的呢?它的灵魂由哈希表和双向链表组成,这两者默契配合,如同舞台上的黄金搭档。哈希表负责快速查找数据,而双向链表则维护数据的访问顺序。每当缓存被访问或修改,那些被触碰的节点就会翩然移动至链表的顶端,就像在人群中优雅起舞。而最遥远的回忆,则沉默地躺在链表的尽头,等待被无情地抹去。
LRU 的魅力不仅仅在于其高效的插入、查询和删除操作,更是它能够自动淘汰最久未使用数据的能力。不管是网络应用中的资源缓存,还是数据库查询结果的缓存,LRU 都能有效减少次数,为用户带来极速体验。
通过阅读本文,你将亲身感受到 LRU 的魔力。它带你穿越缓存世界的迷雾,一览性能优化的奥秘。现在,就让我们勇敢地踏上这场冒险之旅吧!与 LRU 约定一场,让你的系统焕发全新活力,让用户的体验飞跃时空!