LRU算法的实现

Contents

LRU算法的实现,欢迎交流,指正错误。

LRU是Least Recently Used的缩写,即最近最少使用,常用于页面置换算法,是为虚拟页式存储管理服务的。

LRU 算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。

实现方案:

  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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

/**
 * LRU 手动实现
 * LRU 每次淘汰最近最少使用的缓存value
 *
 * 思路:
 * 1、用HashMap作为缓存,实现添加缓存值和更新值
 * 2、通过一个双向链表记录缓存值的使用记录, 最近有使用的放入表头,最近最少使用的放在表尾
 * 3、HashMap中 key 即为搜索查询使用的 key ; value 是双向链表的结点 node
 */
public class LRUCache {

    private static class Node{
        int key;
        int value;
        Node pre;
        Node next;

        public Node(){

        }

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

    }

    private Map<Integer, Node> cache = new HashMap<>();
    private int capacity;
    private int count;
    private Node head, tail;

    public LRUCache(int capacity){
        this.capacity = capacity;
        this.count = 0;
        this.head = new Node();
        this.tail = new Node();

        head.pre = null;
        head.next = tail;
        tail.pre = head;
        tail.next = null;
    }

    /**
     * 从缓存中取值
     * @param key 取值的key
     * @return 若key所对应的值存在则返回,否则返回-1
     */
    public int get(int key){
        Node node = cache.get(key);
        if(node != null){
            moveToHead(node);
            return node.value;
        }else{
            return -1;
        }
    }

    /**
     * 往缓存中添加(更新)值
     * @param key 值对的key
     * @param value 缓存值
     */
    public void put(int key, int value){
        Node node = cache.get(key);
        // 未在缓存中,添加至缓存
        if(node == null){
            node = new Node(key, value);
            cache.put(key, node);
            addNode(node);
            ++count;
            if(count > capacity){ //超出容量
                popTail();
                --count;
            }
        }else{ // 在缓存中, 更新缓存值
            node.value = value;
            moveToHead(node);
        }

    }

    /**
     * 将链表中最后一个节点移除。同时也从缓存中移除
     */
    private void popTail() {
        Node node = tail.pre;
        removeNode(node);
        cache.remove(node.key);
    }

    /**
     * 将节点移动至链表的头部,表示该节点刚添加 或 刚更新 。
     * @param node 节点
     */
    private void moveToHead(Node node) {
        removeNode(node);
        addNode(node);
    }

    /**
     * 添加节点
     * @param node 节点
     */
    private void addNode(Node node) {
        node.pre = head;
        node.next = head.next;
        head.next = node;
        node.next.pre = node;
    }

    /**
     * 移除指定节点
     * @param node 节点
     */
    private void removeNode(Node node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

}
0%