基于双向列表+HashMap实现LRU算法源码实现

算法介绍:
最近最久未使用(Least Recently Used    LRU)算法是⼀种缓存淘汰策略。该算法的思路是,将最近一段时间内最久未使用的页面置换出去。 升级版LRUK算法见

基于LRU-K算法设计本地缓存实现流量削峰https://blog.csdn.net/love254443233/article/details/82598381?spm=1001.2014.3001.5502


import java.util.HashMap;
import java.util.Map;

/**
 * Design a data structure that follows the constraints of a Least Recently Used (LRU) cache.
 * <p>
 * Implement the LRUCache class:
 * <p>
 * LRUCache(int capacity) Initialize the LRU cache with positive size capacity.
 * int get(int key) Return the value of the key if the key exists, otherwise return -1.
 * void put(int key, int value) Update the value of the key if the key exists. Otherwise, add the key-value pair to the cache. If the number of keys exceeds the capacity from this operation, evict the least recently used key.
 * The functions get and put must each run in O(1) average time complexity.
 */
public class LRUCache {

    static class Node {
        Node prev;
        Node next;

        int key;
        int value;

        public Node() {
        }

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

    Map<Integer, Node> cachMap = new HashMap<>(16);
    Node head;
    Node end;

    int size;
    int capacity;

    public LRUCache(int capacity) {
        this.size = 0;
        this.capacity = capacity;
        head = new Node();
        end = new Node();
        head.next = end;
        end.prev = head;
    }

    public int get(int key) {
        Node node = cachMap.get(key);
        if (node == null) {
            return -1;
        }
        // 移动到链表头
        moveToHead(node, head);
        return node.value;
    }

    public void put(int key, int value) {
        Node node = cachMap.get(key);
        if (node == null) {
            Node data = new Node(key, value);
            cachMap.put(key, data);
            addToHead(data, head);
            ++size;
            if (size > capacity) {
                cachMap.remove(end.prev.key);
                delete(end.prev);
                --size;
            }
            return;
        }

        node.value = value;
        moveToHead(node, head);
    }

    /**
     * 添加到链表头
     *
     * @param node 数据节点
     * @param head 头节点
     */
    private static void addToHead(Node node, Node head) {
        node.next = head.next;
        node.prev = head;
        head.next = node;
        node.next.prev = node;
    }

    /**
     * 移除当前节点
     *
     * @param data 数据节点
     */
    private static void delete(Node data) {
        if (data.prev != null) {
            Node prev = data.prev;
            prev.next = data.next;
            data.next.prev = prev;
        }
    }

    /**
     * 把节点移动到链表头
     *
     * @param node 节点
     * @param head 头节点
     */
    private static void moveToHead(Node node, Node head) {
        // 移除node
        delete(node);

        // 把node添加到链表头
        addToHead(node, head);
    }
}

单元测试

import junit.framework.TestCase;
import org.junit.Assert;

public class LRUCacheTest extends TestCase {

    public void testGet() {
        LRUCache lruCache = new LRUCache(2);
        // node 为空,结果为-1
        Assert.assertEquals(-1, lruCache.get(1));

        // node存在
        lruCache.put(1, 2);
        Assert.assertEquals(2, lruCache.get(1));

        // node存在,重复put
        lruCache.put(1, 3);
        Assert.assertEquals(3, lruCache.get(1));

        // cache数量超过容器数量,会移除链表尾节点
        lruCache.put(2, 3);
        lruCache.put(3, 4);
        Assert.assertEquals(-1, lruCache.get(1));
    }
}

猜你喜欢

转载自blog.csdn.net/love254443233/article/details/132366152
今日推荐