LeetCode--单链表--146.LRU缓存

146.LRU缓存(❤❤)

LRU原理,利用双向链表加hashMap实现
class LRUCache {
    private HashMap<Integer,Node>map;
    private DoubleList cache;
    private int capacity;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        map = new HashMap<>();
        cache = new DoubleList();
    }
    
    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }
        makeRecently(key);
        return map.get(key).val;
    }
    
    public void put(int key, int value) {
        if (map.containsKey(key)) {
        // 删除旧的数据
        deleteKey(key);
        // 新插入的数据为最近使用的数据
        addRecently(key, value);
        return;
    }
    
    if (capacity == cache.size()) {
        // 删除最久未使用的元素
        removeLeastRecently();
    }
    // 添加为最近使用的元素
        addRecently(key, value);

    }
    private void makeRecently(int key){
        Node x = map.get(key);
        System.out.println("recently:"+x.key);
        cache.removeList(x);
        cache.addList(x); //重新插回队尾
    }
    private void addRecently(int key,int val){
        Node x = new Node(key,val);
        cache.addList(x);
        map.put(key,x);
    }
    /* 删除最久未使用的元素 */
    private void removeLeastRecently() {
    // 链表头部的第一个元素就是最久未使用的
    
    Node deletedNode = cache.removeListFirst();
    // 同时别忘了从 map 中删除它的 key
    int deletedKey = deletedNode.key;
    System.out.println(deletedKey);
    map.remove(deletedKey);
    }

    private void deleteKey(int key){
        Node x = map.get(key);
        cache.removeList(x);
        map.remove(key);
    }
}
class Node{
    public Node next;
    public Node pre;
    public int key;
    public int val;
    public Node(int key,int val){
        this.key = key;
        this.val = val;
    }
}

class DoubleList{
    private Node head;
    private Node tail;
    private int size;
    public DoubleList(){
        head = new Node(0,0);
        tail = new Node(0,0);
        head.next = tail;
        tail.pre =head;
        size = 0;
    }
    public void addList(Node x){
        //从尾部插入
        x.pre = tail.pre;
        tail.pre.next=x;
        x.next = tail;
        tail.pre = x;
        size++;
    }
    public void removeList(Node x){
        x.pre.next = x.next;
        x.next.pre = x.pre;
        size--;
    }
    public Node removeListFirst(){
        if(head.next==tail){
            return null;
        }
        //head.next = head.next.next;
        //head.next.next.pre=head; 要返回删除的这个节点
        Node first = head.next;
        removeList(first);
        return first;
    }
    public int size(){
        return size;
    }

}
/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */
利用Java内置LinkedHashMap实现
class LRUCache {
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
    public LRUCache(int capacity) { 
        this.cap = capacity;
    }
    
    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        // 将 key 变为最近使用
        makeRecently(key);
        return cache.get(key);
    }
    
    public void put(int key, int val) {
        if (cache.containsKey(key)) {
            // 修改 key 的值
            cache.put(key, val);
            // 将 key 变为最近使用
            makeRecently(key);
            return;
        }
        
        if (cache.size() >= this.cap) {
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }
        // 将新的 key 添加链表尾部
        cache.put(key, val);
    }
    
    private void makeRecently(int key) {
        int val = cache.get(key);
        // 删除 key,重新插入到队尾
        cache.remove(key);
        cache.put(key, val);
    }
}

LinkedHashMap

虽然增加了时间和空间上的开销,但是通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序该迭代顺序可以是插入顺序或者是访问顺序。

关 注 点 结 论
LinkedHashMap是否允许空 Key和Value都允许空
LinkedHashMap是否允许重复数据 Key重复会覆盖、Value允许重复
LinkedHashMap是否有序 有序
LinkedHashMap是否线程安全 非线程安全
public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{
private transient Entry<K,V> header;
/**
 * The iteration ordering method for this linked hash map: true
 * for access-order, false for insertion-order.
 * true表示最近最少使用次序,false表示插入顺序
 */
private final boolean accessOrder;
    ...
}

LinkedHashMap是HashMap的子类,自然LinkedHashMap也就继承了HashMap中所有非private的方法。

关于HashMap原理做了点笔记,也没有太理解,参考文章:
https://blog.csdn.net/qq_42194397/article/details/126059459?spm=1001.2014.3001.5501

你可能感兴趣的:(Leetcode题解,leetcode,缓存,链表)