LRU(Least Recently Used):最近最少使用算法简介及其代码实现(双向链表+HashMap)
简介
- 新增元素时,若达到最大容量,则淘汰最近最少使用的元素。
- 淘汰规则示意如下图,假设最大容量为3:

双向链表 + HashMap 实现LRU算法(Java)
- get()和put()操作的时间复杂度均为o(1)
- get(key)操作
- 若map.get(key)为空,则返回null;
- 若map.get(key)不为空,则将map.get(key)得到的node插入头结点后并返回node.val
- put(key, value)操作
- 若map.get(key)为空,则新建node节点,头插法插入双向链表,并加入map:map.put(key, node)。此时若size>capacity,说明超出最大容量,则移除双向链表中的尾结点,同时在map中移除尾结点对应的key。
- 若map.get(key)不为空,则将map.get(key)得到的node插入头结点后并更新val:node.val = value
- 数据结构和具体代码实现如下:

import java.util.HashMap;
import java.util.Map;
public class LRUCache<K, V> {
class Node<K, V> {
K key;
V val;
Node pre;
Node next;
public Node() {
}
public Node(K key, V val, Node pre, Node next) {
this.key = key;
this.val = val;
this.pre = pre;
this.next = next;
}
}
private Node head;
private Node tail;
private Map<K, Node> map;
private int capacity;
private int size;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
map = new HashMap<K, Node>();
size = 0;
}
public void moveToHead(Node node) {
node.pre.next = node.next;
node.next.pre = node.pre;
node.pre = head;
node.next = head.next;
head.next = node;
node.next.pre = node;
}
public Node removeLast() {
Node last = tail.pre;
last.pre.next = tail;
tail.pre = last.pre;
return last;
}
public V get(K key) {
if (map.get(key) == null) return null;
Node node = map.get(key);
moveToHead(node);
return (V) node.val;
}
public void put(K key, V value) {
Node node = map.get(key);
if (node != null) {
moveToHead(node);
node.val = value;
return;
}
node = new Node(key, value, head, head.next);
head.next = node;
node.next.pre = node;
map.put(key, node);
size++;
if (size > capacity) {
Node last = removeLast();
map.remove(last.key);
size--;
}
}
@Override
public String toString() {
Node node = head;
StringBuilder sb = new StringBuilder();
while(node.next!=tail){
node = node.next;
sb.append(node.key + "=" + node.val+" ");
}
return sb.toString();
}
public static void main(String[] args) {
LRUCache<Integer, String> LRUCache =
new LRUCache<>(3);
LRUCache.put(1, "a");
System.out.println(LRUCache.toString());
LRUCache.put(2, "b");
System.out.println(LRUCache.toString());
LRUCache.put(3, "c");
System.out.println(LRUCache.toString());
LRUCache.put(4, "d");
System.out.println(LRUCache.toString());
System.out.println(LRUCache.get(3));
System.out.println(LRUCache.toString());
}
}
- 上述代码输出如下:
