1.双向列表实现RUL
public class LRUCache {
LinkedList<Node> cache;
int capacity;
public LRUCache(LinkedList<Node> cache, int capacity) {
this.cache = cache;
this.capacity = capacity;
}
public int get(int key){
int result = -1;
//队列的逆向迭代器
Iterator<Node> iterator = cache.descendingIterator();
while (iterator.hasNext()){
Node node = iterator.next();
if(node.key == key){
result = node.val;
iterator.remove();
//添加到列表尾部
put(key,node.val);
break;
}
}
return result;
}
public void put(int key , int value){
Iterator<Node> iterator = cache.iterator();
while (iterator.hasNext()){
Node node = iterator.next();
if(node.key == key){
iterator.remove();
break;
}
}
if(capacity == cache.size()){
//缓存已经满了 删除最近最少访问的 一个元素(表头)
cache.removeFirst();
}
cache.add(new Node(key,value));
}
class Node {
int key;
int val;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
}
public static void main(String[] args) {
LRUCache cache = new LRUCache(new LinkedList<>(),10);
for(int i = 0 ; i < 10 ; i++){
cache.put(i,i);
}
cache.get(1);
cache.get(3);
cache.put(12,12);
System.out.println(cache.get(3));
}
}
2.使用LinkedHashMap实现
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Set;
/**
*
* LinkedHashMap 实现
* put /get 操作 O(1)
* 特殊情况:缓存已满,需要删除链表头
* @author FYG
* @date 2020/10/28
* @description
*/
public class LRUCache2 {
LinkedHashMap<Integer,Integer> cache;
int capacity ;
public LRUCache2(int capacity) {
this.cache = new LinkedHashMap<>(capacity);
this.capacity = capacity;
}
public int get(int key){
if(!cache.containsKey(key)){
return -1;
}
Integer val = cache.get(key);
//从链表中删除
cache.remove(key);
//添加到链尾
cache.put(key,val);
return val;
}
public void put(int key,int value){
if(cache.containsKey(key)){
cache.remove(key);
}
if(cache.size() == capacity){
//cache已经满了 删除表头
Set<Integer> keySet = cache.keySet();
Iterator<Integer> iterator = keySet.iterator();
cache.remove(iterator.hasNext());
}
//添加到链尾
cache.put(key,value);
}
}
3.LinkedHashMap 本身内部有一个触发条件则自动执行的方法:删除最老元素(最近最少使用的元素)
/**
* LinkedHashMap 本身内部有一个触发条件则自动执行的方法:删除最老元素(最近最少使用的元素)
* 由于最近最少使用元素是 LinkedHashMap 内部处理
* 故我们不再需要维护 最近访问元素放在链尾,get 时直接访问/ put 时直接存储
*
* @author FYG
* @date 2020/10/28
* @description
*/
public class LRUCache3 {
private Map<Integer, Integer> map;
private int capacity;
public LRUCache3(int capacity) {
this.capacity = capacity;
this.map = new LinkedHashMap<Integer, Integer>(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity; // 容量大于capacity 时就删除
}
};
}
public int get(int key) {
return map.getOrDefault(key, -1);
}
public void put(int key, int val) {
map.put(key, val);
}
}
最后一种算法我们从源码看一下
HashMap.java
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
...
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e); // 这里是把当前的节点放到对尾部
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict) ; // 这里移除最老的元素
return null;
}
LinkedHashMap.java
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
//我们重写的removeEldestEntry 判断是否删除最老的元素
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}