您的位置:首页 > 编程语言 > Java开发

LeetCode | LRU Cache

2014-06-10 11:07 363 查看
原题描述:

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.

解题思路:

      题目要求算法能根据键值对随机存取缓存,我们很容易就能想到使用哈希表来实现。但是题目还要求缓存是LRU(Least Recently Used)形式的,即在更新缓存时采用最近最少使用原则,这就需要数据结构能记录缓存的命中情况:每次有缓存被命中都需要将其标记为最近使用,当缓存大小超出容量时,需要删除最久未被使用的缓存。

      在Java中,正好有这么一种哈希表,可以记录数据的访问顺序,它就是LinkedHashMap。借助于LinkedHashMap,我们可以很容易地实现LRU
Cache,代码如下:

import java.util.LinkedHashMap;

public class LRUCache extends LinkedHashMap<Integer, Integer> {
private int capacity;

public LRUCache1(int capacity) {
super(capacity+1, 0.75f, true);
this.capacity = capacity;
}

@Override
protected boolean removeEldestEntry(
java.util.Map.Entry<Integer, Integer> eldest) {
return size() > capacity; //当缓存大小超出容量时,移除最久未被使用的缓存
}

public int get(int key) {
return super.get(key) != null ? super.get(key) : -1;
}

public void set(int key, int value) {
super.put(key, value);
}

public int size() {
return super.size();
}

}
       LinkedHashMap的方案虽然简便,但是它毕竟不是基本的数据结构,从算法设计的角度来说,我们还是需要一个使用基本数据结构来实现的方案。参考LinkedHashMap类的内部实现原理,我们可以通过哈希表+双链表的组合来实现LRU
Cache。由哈希表来实现根据键值对(值为双链表结点)随机存取,由双链表来维护缓存的命中情况:最近使用的缓存在链表头结点,最久未使用的缓存在链表尾结点,当缓存被命中时,将其移至链表头结点,当缓存大小超出容量时,直接删除链表尾结点。代码实现如下:

import java.util.HashMap;

public class LRUCache {

class CacheNode {
public int key;
public int value;
public CacheNode pre;
public CacheNode next;

public CacheNode(int key, int value) {
this.key = key;
this.value = value;
}
}

private int capacity;
private int size = 0;
private HashMap<Integer, CacheNode> map = new HashMap<>();
private CacheNode head;
private CacheNode tail;

public LRUCache(int capacity) {
this.capacity = capacity;
head = null;
tail = null;
}

private void removeNode(CacheNode node) {
CacheNode pre = node.pre;
CacheNode next = node.next;
if (pre != null) {
pre.next = next;
} else {
head = next;
}
if (next != null) {
next.pre = pre;
} else {
tail = pre;
}
}

private void setHead(CacheNode node) {
node.next = head;
node.pre = null;
if (head != null) {
head.pre = node;
}
head = node;
if (tail == null) {
tail = node;
}
}

public void set(int key, int value) {
if (map.containsKey(key)) {
CacheNode oldNode = map.get(key);
oldNode.value = value;
removeNode(oldNode);
setHead(oldNode);
} else {
CacheNode newNode = new CacheNode(key, value);
if (size < capacity) {
size++;
} else {
map.remove(tail.key);
tail = tail.pre;
if (tail != null) {
tail.next = null;
}
}
setHead(newNode);
map.put(key, newNode);
}
}

public int get(int key) {
if (map.containsKey(key)) {
CacheNode lastest = map.get(key);
removeNode(lastest);
setHead(lastest);
return lastest.value;
} else {
return -1;
}
}

}


参考文献: http://www.programcreek.com/2013/03/leetcode-lru-cache-java/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息