题目:实现一个LRU Cache
算法:
- 双向链表 + HashMap
- get:若节点不存在,返回-1;否则返回节点value,并将节点调整到head
- set(key, value):
- 若key已经存在:更新value,并将节点调整到head;
- 若key不存在:若cache容量足够,将节点压入链表头部;若cache容量不足,淘汰链表尾部节点,并将新节点压入链表头部
import java.util.HashMap;
public class LRUCache {
/**
* Structure
*
* @author ouyangyewei
*/
public class CacheNode {
public int key;
public int value;
public CacheNode prev;
public CacheNode next;
public CacheNode() {
// nothing
}
public CacheNode(int key, int value) {
this.key = key;
this.value = value;
this.prev = null;
this.next = null;
}
}
private int capacity;
private int currentCapacity;
private CacheNode head;
private CacheNode tail;
private HashMap<Integer, CacheNode> hashNode;
public LRUCache(int capacity) {
this.capacity = capacity;
this.currentCapacity = 0;
this.head = null;
this.tail = null;
this.hashNode = new HashMap<Integer, CacheNode>();
}
public int get(int key) {
CacheNode node = hashNode.get(key);
if (null == node) {
return -1;
} else {
moveToHead(node);
return node.value;
}
}
public void set(int key, int value) {
if (null == hashNode.get(key)) {
/** cacheNode is not exists! */
CacheNode node = new CacheNode(key, value);
if (currentCapacity < capacity) {
/** enough capacity for add a node */
addToHead(node);
++currentCapacity;
} else {
/** over the maximum capacity */
removeLeastUseNode();
addToHead(node);
currentCapacity = capacity;
}
hashNode.put(key, node);
} else {
/** cacheNode is already exists */
CacheNode node = hashNode.get(key);
node.value = value;
moveToHead(node);
hashNode.put(key, node);
}
}
/**
* Move a node to list's head
* @param node
*/
public void moveToHead(CacheNode node) {
if (null != node.prev) {
/** node locate behind the list's head */
CacheNode front = node.prev;
CacheNode behind = node.next;
if (null == behind) {
/** node locate at the list's tail */
front.next = behind;
tail = front;
} else {
front.next = behind;
behind.prev = front;
}
node.prev = null;
node.next = head;
head.prev = node;
head = node;
}
}
/**
* Add a node to list's head.
* @param node
*/
public void addToHead(CacheNode node) {
if (null == head) {
/** list is empty */
head = node;
tail = node;
} else {
/** list is not empty */
node.next = head;
head.prev = node;
head = node;
}
}
/**
* Remove the least use node, it means remove
* the list's tail node.
*/
public void removeLeastUseNode() {
if (null != tail.prev) {
hashNode.remove(tail.key);
tail = tail.prev;
tail.next = null;
} else {
/** list has only one node */
hashNode.remove(tail.key);
head = null;
tail = null;
}
}
// public static void main(String[] args) {
// LRUCache lruCache = new LRUCache(4);
// lruCache.set(1, 1);
// lruCache.set(0, 0);
// lruCache.get(1);
// lruCache.get(0);
// lruCache.set(2, 2);
// lruCache.set(4, 4);
// lruCache.get(1);
// lruCache.get(0);
// lruCache.get(0);
// lruCache.set(8, 8);
// lruCache.set(7, 7);
// lruCache.set(5, 5);
// lruCache.set(4, 4);
// lruCache.set(3, 3);
// lruCache.set(2, 2);
// lruCache.get(3);
// lruCache.get(4);
// LRUCache lruCache = new LRUCache(1);
// lruCache.set(2, 1);
// System.out.println(lruCache.get(2));
// lruCache.set(3, 2);
// System.out.println(lruCache.get(2));
// System.out.println(lruCache.get(3));
// LRUCache lruCache = new LRUCache(2);
// lruCache.set(2, 1);
// lruCache.set(1, 2);
// lruCache.set(2, 3);
// lruCache.set(4, 1);
// System.out.println(lruCache.get(1));
// System.out.println(lruCache.get(2));
// }
}