这篇文章主要讲解了“JavaScript怎么实现LRU缓存淘汰算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript怎么实现LRU缓存淘汰算法”吧!
如何实现LRU缓存淘汰算法?
LRU(Least Recently Used)缓存淘汰算法是一种常见的缓存淘汰策略,它的核心思想是优先淘汰最近最少使用的缓存数据,以保证缓存中的数据始终是最热门的。
使用哈希表和双向链表
LRU缓存淘汰算法的核心在于如何快速定位最近最少使用的缓存数据,这可以通过哈希表和双向链表的结合来实现。具体来说,我们可以使用一个哈希表来存储缓存数据的键值对,同时使用一个双向链表来维护缓存数据的访问顺序,每次访问缓存时,我们将访问的数据节点移动到链表头,当缓存满时,淘汰链表尾部的节点即可。
哈希表实现LRU缓存淘汰算法
下面是一个使用哈希表实现LRU缓存淘汰算法的例子,假设我们要实现一个最大容量为3的缓存:
import java.util.HashMap; import java.util.Map; class LRUCache<K, V> { private int capacity; private Map<K, Node<K,V>> cache; private Node<K,V> head; private Node<K,V> tail; public LRUCache(int capacity) { this.capacity = capacity; this.cache = new HashMap<>(); this.head = new Node<>(null, null); this.tail = new Node<>(null, null); this.head.next = this.tail; this.tail.prev = this.head; } public V get(K key) { if (!cache.containsKey(key)) { return null; } Node<K,V> node = cache.get(key); remove(node); addFirst(node); return node.value; } public void put(K key, V value) { if (cache.containsKey(key)) { Node<K,V> node = cache.get(key); node.value = value; remove(node); addFirst(node); } else { if (cache.size() == capacity) { Node<K,V> node = removeLast(); cache.remove(node.key); } Node<K,V> node = new Node<>(key, value); cache.put(key, node); addFirst(node); } } private void remove(Node<K,V> node) { node.prev.next = node.next; node.next.prev = node.prev; } private void addFirst(Node<K,V> node) { node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } private Node<K,V> removeLast() { Node<K,V> node = tail.prev; remove(node); return node; } private static class Node<K, V> { K key; V value; Node<K,V> prev; Node<K,V> next; public Node(K key, V value) { this.key = key; this.value = value; } } }
在这个例子中,我们使用了一个哈希表
cache来存储缓存数据的键值对,同时使用了一个双向链表来维护缓存数据的访问顺序,其中
head和
tail分别表示链表头和链表尾,每次访问缓存时,我们将访问的数据节点移动到链表头,当缓存满时,淘汰链表尾部的节点即可。
注意,为了方便起见,我们在链表头和链表尾分别添加了一个哨兵节点
head和
tail,这样就不需要在代码中处理链表为空的情况了。
下面是一个使用双向链表实现LRU缓存淘汰算法的例子,假设我们要实现一个最大容量为3的缓存:
import java.util.HashMap; import java.util.Map; class LRUCache<K, V> { private int capacity; private Map<K, Node<K,V>> cache; private Node<K,V> head; private Node<K,V> tail; public LRUCache(int capacity) { this.capacity = capacity; this.cache = new HashMap<>(); this.head = new Node<>(null, null); this.tail = new Node<>(null, null); this.head.next = this.tail; this.tail.prev = this.head; } public V get(K key) { if (!cache.containsKey(key)) { return null; } Node<K,V> node = cache.get(key); remove(node); addFirst(node); return node.value; } public void put(K key, V value) { if (cache.containsKey(key)) { Node<K,V> node = cache.get(key); node.value = value; remove(node); addFirst(node); } else { if (cache.size() == capacity) { Node<K,V> node = removeLast(); cache.remove(node.key); } Node<K,V> node = new Node<>(key, value); cache.put(key, node); addFirst(node); } } private void remove(Node<K,V> node) { node.prev.next = node.next; node.next.prev = node.prev; } private void addFirst(Node<K,V> node) { node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } private Node<K,V> removeLast() { Node<K,V> node = tail.prev; remove(node); return node; } private static class Node<K, V> { K key; V value; Node<K,V> prev; Node<K,V> next; public Node(K key, V value) { this.key = key; this.value = value; } } }
在这个例子中,我们使用了一个哈希表
cache来存储缓存数据的键值对,同时使用了一个双向链表来维护缓存数据的访问顺序,其中
head和
tail分别表示链表头和链表尾,每次访问缓存时,我们将访问的数据节点移动到链表头,当缓存满时,淘汰链表尾部的节点即可。
注意,为了方便起见,我们在链表头和链表尾分别添加了一个哨兵节点
head和
tail,这样就不需要在代码中处理链表为空的情况了。