Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and set
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value)
- Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
题目给出的框架是:
class LRUCache{
public:
LRUCache(int capacity) {
}
int get(int key) {
}
void set(int key, int value) {
}
};
就是实现两个函数。这个结构中有key-value对,所以需要一个map 进行存储。还有为了插入删除方便和把已经出现的结点放在存储结构的最开始位置,我们使用双向链表数据结构进行数据的连接。其实这个过程在操作系统中讲到的换页算法是一致的。
简单执行流程:比如我cache只有4这么大,现在有很多元素1,2,2,4,2,5,3
cache income:1
1
cache income:2
2 1
cache income:1
1 2
cache income:4
4 1 2
cache income:2
2 4 1
cache income:5
5 2 4 1
cache income:3
3 5 2 4
在网上看到百度笔试用到了这道题,很好去考察数据结构的理解和应用。
进行编码实现:
package LRU_cache;
import java.util.*;
public class LRUCache {
public LRUCache(int capacity) {
this.capacity = capacity;
this.cacheList = new CacheNodeList(capacity);
this.cacheMap = new HashMap<Integer, CacheNode>();
}
public int get(int key) {
CacheNode request = cacheMap.get(key);
if (request == null)
return -1;
cacheList.shiftToFirst(request);
return request.val;
}
public void set(int key, int value) {
if (cacheMap.containsKey(key)) {
CacheNode request = cacheMap.get(key);
request.val = value;
cacheList.shiftToFirst(request);
}
else {
if (cacheMap.size() == capacity) {
CacheNode node = cacheList.removeLast();
cacheMap.remove(node.key);
}
CacheNode newCache = new CacheNode(key, value);
cacheList.insertFirst(newCache);
cacheMap.put(key, newCache);
}
}
private int capacity;
private CacheNodeList cacheList;
private HashMap<Integer, CacheNode> cacheMap;
}
// 每个结点的存储结构。
class CacheNode {
int key;
int val;
CacheNode prev;
CacheNode next;
public CacheNode(int key, int val) {
this.key = key;
this.val = val;
this.prev = null;
this.next = null;
}
}
//双向链表的存储数据结构。
class CacheNodeList {
public CacheNodeList(int capacity) {
head = new CacheNode(0, 0);
tail = new CacheNode(0, 0);
head.next = tail;
tail.prev = head;
}
//结点通过头部插入双向链表。
public void insertFirst(CacheNode node) {
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
// 头尾 head 与 tail不存放东西仅为了插入双向插入删除方便。
public CacheNode removeLast() {
CacheNode lastNode = tail.prev;
tail.prev = tail.prev.prev;
tail.prev.next = tail;
return lastNode;
}
public void shiftToFirst(CacheNode node) {
//先把node结点删除,在插入在头部。
node.prev.next = node.next;
node.next.prev = node.prev;
this.insertFirst(node);
}
public CacheNode head;
public CacheNode tail;
}