WHCSRL 技术网

算法-LRU 实现

1. LRU 缓存实现

设计实现一个 LRU (最近最少使用) 缓存机制, 实现 LRUCache 类,leetcode传送门

  1. LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  2. int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
  3. void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

2. 设计实现

  1. 使用一个 Map 来保存实际的键值对元素,实现 O(1) 查找
  2. 使用自定义双向链表来维护访问关系,分别定义头尾指针,最近访问的元素移动到链表尾部,链表头即为最近最少使用的
public class LRUCache {
   
    private Integer capacity;

    private int size;

    private LinkedNode head, tail;

    private Map<Integer, LinkedNode> cache;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.size = 0;

        cache = new HashMap<>();
        head = new LinkedNode();
        tail = new LinkedNode();
        head.next = tail;
        tail.prev = head;
    }

    public int get(int key) {
        LinkedNode node = cache.get(key);
        if (node == null) {
            return -1;
        }
        // 如果 key 存在,先通过哈希表定位,因为访问过了,需将其移动到尾部
        moveToTail(node);
        return node.value;
    }

    public void put(int key, int value) {
        LinkedNode node = cache.get(key);
        // 不存在则新建节点
        if (node == null) {
            if (size == capacity) {
                // 删除头节点的 next 节点
                LinkedNode header = removeNode(head.next);
                cache.remove(header.key);
                size--;
            }

            node = new LinkedNode(key, value);
            cache.put(key, node);
            addToTail(node);
            size++;
        } else {
            // 存在则需要先将其从双向链表中移除,再移动节点到尾部
            node.value = value;
            moveToTail(node);
        }
    }

    private void addToTail(LinkedNode node) {
        LinkedNode pre = tail.prev;

        tail.prev = node;
        node.next = tail;

        pre.next = node;
        node.prev = pre;
    }

    private void moveToTail(LinkedNode node) {
        removeNode(node);
        addToTail(node);
    }

    private LinkedNode removeNode(LinkedNode node) {
        LinkedNode pre = node.prev;
        LinkedNode next = node.next;

        pre.next = next;
        next.prev = pre;

        return node;
    }


    static class LinkedNode {
        int key;
        int value;
        LinkedNode prev;
        LinkedNode next;

        public LinkedNode() {
        }

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
推荐阅读