实现LRU缓存
本文最后更新于 5 天前。

下面的代码是一开始自己写的错误写法,不仅时间复杂度无法做到$O(1)$,(因为LinkedList的删除中间元素是$O(n)$),而且删除后LinkedList后序元素的下标也会改变,而key2index中的下标没有改变,所以会导致错误的结果。


//class LRUCache {
//    private final Map<Integer, Integer> key2value;
//    private final List<Integer> queue;
//    private final Map<Integer, Integer> key2index;
//    private final int capacity;
//
//    public LRUCache(int capacity) {
//        this.key2value = new HashMap<>();
//        this.queue = new LinkedList<>();
//        this.key2index = new HashMap<>();
//        this.capacity = capacity;
//    }
//
//    public int get(int key) {
//        if(key2value.containsKey(key)){
//            int idx = key2index.get(key);
//            queue.remove(idx);
//            queue.addLast(key);
//            key2index.put(key, queue.size() - 1);
//            return key2value.get(key);
//        }
//        return -1;
//    }
//
//    public void put(int key, int value) {
//        if(!key2value.containsKey(key)){
//            if(key2value.size() == capacity){
//                int removeKey = queue.removeFirst();
//                key2value.remove(removeKey);
//                key2index.remove(removeKey);
//            }
//            key2value.put(key, value);
//            queue.addLast(key);
//            key2index.put(key, queue.size() - 1);
//        } else {
//            int idx = key2index.get(key);
//            queue.remove(idx);
//            queue.addLast(key);
//            key2index.put(key, queue.size() - 1);
//            key2value.put(key, value);
//        }
//    }
//}

下面是用java的LinkedHashMap实现的代码,LinkedHashMap维护了一个双向链表和哈希表,具体细节在注释中

class LRUCache extends LinkedHashMap<Integer, Integer> {   // 直接继承LinkedHashMap
    private int capacity;                                  // cache容量

    public LRUCache(int capacity) {
        super(capacity, 0.75F, true); // accessOrder设为true,就可以按照访问顺序排序双向链表,默认是插入顺序
        this.capacity = capacity;
    }

    public int get(int key) {
        return super.getOrDefault(key, -1);
    }

    public void put(int key, int value) {                  // put后可能超出容量,LinkedHashMap会自动根据重写的removeEldestEntry删除最旧的元素
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity;
    }
}

下面是手写的代码,使用了手写的双向链表(链表节点类和头尾哑节点)和直接将key映射到链表节点的HashMap,最近最少访问的节点位于head.next。不能用linkedList,因为它的remove只能是$O(n)$的,我们的remove需要直接操作指针达到$O(1)$。用哑节点是为了方便删除和插入的操作

class LRUCache {
    class LinkedListNode {
        int key;
        int value;
        LinkedListNode next;
        LinkedListNode prev;
        public LinkedListNode(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }
    private LinkedListNode head;
    private LinkedListNode tail;
    private final Map<Integer, LinkedListNode> map;
    private final int capacity;

    public LRUCache(int capacity) {
        head = new LinkedListNode(0, 0);
        tail = new LinkedListNode(0, 0);
        head.next = tail;
        tail.prev = head;
        this.capacity = capacity;
        map = new HashMap<>();
    }

    public int get(int key) {
        if(map.containsKey(key)) {
            LinkedListNode node = map.get(key);
            node.prev.next = node.next;
            node.next.prev = node.prev;
            node.prev = tail.prev;
            tail.prev.next = node;
            tail.prev = node;
            node.next = tail;
            return node.value;
        } else {
            return -1;
        }
    }

    public void put(int key, int value) {
        if(map.containsKey(key)) {
            LinkedListNode node = map.get(key);
            node.value = value;
            node.prev.next = node.next;
            node.next.prev = node.prev;
            node.prev = tail.prev;
            tail.prev.next = node;
            tail.prev = node;
            node.next = tail;
        } else {
            if(map.size() == capacity) {
                LinkedListNode node = head.next;
                map.remove(node.key);
                head.next = node.next;
                node.next.prev = head;
            }
            LinkedListNode node = new LinkedListNode(key, value);
            map.put(key, node);
            node.prev = tail.prev;
            tail.prev.next = node;
            tail.prev = node;
            node.next = tail;
        }
    }
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇