手写Redis淘汰策略中lru算法(删除最近未使用的值) java版

Posted 是Cc哈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手写Redis淘汰策略中lru算法(删除最近未使用的值) java版相关的知识,希望对你有一定的参考价值。

1.题目描述:请见leetcode (LRU缓存机制

2.实现思路:
通过HashMap + 双向链表实现
HashMap:保证查询的时间复杂度是O(1)
双向链表:链表特性,增删元素速度快,链表由头节点+中间节点+尾节点构成,每个节点有前节点和后节点,构成一个双向队列。

3.图解:

put方法:先判断当前节点数量是否等于设置的catchsize,
若等于,则删除tail节点的上一个节点,实现删除最长时间未使用的功能
若小于,再判断是否已经存在这个key了,
若存在,则修改value,再将这个节点放到head节点之后,删除原节点
若不存在,将增加的节点添加到head节点之后

get方法:先判断是否存在这个key
若不存在,返回-1
若存在,获取value值,并将该节点放到head节点之后,并删除原节点,这样做是为了表示该节点最近被使用过。

3.代码实现:

package com.chenchen.demo;
import java.util.HashMap;
import java.util.Map;

/**
 * 手写LRU算法
 * @author chenchen
 */
public class LRUCatchDemo 

    // Node节点
    static class Node<K, V> 
        // key
        K key;
        // value
        V value;
        // 前节点
        Node<K, V> prev;
        // 后节点
        Node<K, V> next;

        public Node() 
            this.prev = null;
            this.next = null;
        

        public Node(K key, V value) 
            this.key = key;
            this.value = value;
        
    

    // 双向队列
    class DoubleLinkedList<K, V> 

        // 头节点
        Node<K, V> head;
        // 尾节点
        Node<K, V> tail;

        DoubleLinkedList() 
            head = new Node<>();
            tail = new Node<>();
            this.head.next = this.tail;
            this.tail.prev = this.head;
        

        // 向队列中添加Node节点到头节点的下一个
        public void addHead(Node<K, V> node) 
            node.next = this.head.next;
            node.prev = this.head;
            this.head.next.prev = node;
            this.head.next = node;
        

        // 向队列删除一个节点
        public void removeNode(Node<K, V> node) 
            node.next.prev = node.prev;
            node.prev.next = node.next;
            node.prev = null;
            node.next = null;
        

        // 找出队列中最长时间未使用的节点
        public Node<K, V> getLast() 
            return this.tail.prev;
        
    

    // DoubleLinkedList的容量
    private static int catchSize;
    private static Map<Integer, Node<Integer, Integer>> map;
    private static DoubleLinkedList<Integer,Integer> doubleLinkedList;

    public LRUCatchDemo(int catchSize) 
        this.catchSize = catchSize;
        map = new HashMap<>();
        doubleLinkedList = new DoubleLinkedList<>();
    

    // 获取get方法
    public static int get(int key) 
        if (!map.containsKey(key)) 
            return -1;
         else 
            Node<Integer, Integer> node = map.get(key);
            // 使用后,需将该节点放到头节点
            doubleLinkedList.removeNode(node);
            doubleLinkedList.addHead(node);
            return node.value;
        
    

    // 添加put方法
    public static void put(Integer key, Integer value) 
        // 如果存在key则更新value值
        if (map.containsKey(key)) 
            Node<Integer, Integer> node = map.get(key);
            node.value = value;
            map.put(key, node);
            doubleLinkedList.removeNode(node);
            doubleLinkedList.addHead(node);
         else 
            // 达到容量峰值,删除最久未使用的node
            if (map.size() == catchSize) 
                Node<Integer, Integer> last = doubleLinkedList.getLast();
                map.remove(last.key);
                doubleLinkedList.removeNode(last);
            
            Node<Integer, Integer> node = new Node<>(key, value);
            map.put(key, node);
            doubleLinkedList.addHead(node);
        
    

    public static void main(String[] args) 
        LRUCatchDemo lRUCache = new LRUCatchDemo(2);
        LRUCatchDemo.put(1, 1); // 缓存是 1=1
        System.out.println(LRUCatchDemo.map.keySet());
        LRUCatchDemo.put(2, 2); // 缓存是 1=1, 2=2
        System.out.println(LRUCatchDemo.map.keySet());
        System.out.println(LRUCatchDemo.get(1));    // 返回 1
        LRUCatchDemo.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 1=1, 3=3
        System.out.println(LRUCatchDemo.map.keySet());
        System.out.println(LRUCatchDemo.get(2));    // 返回 -1 (未找到)
        LRUCatchDemo.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 4=4, 3=3
        System.out.println(LRUCatchDemo.map.keySet());
        System.out.println(LRUCatchDemo.get(1));    // 返回 -1 (未找到)
        System.out.println(LRUCatchDemo.get(3));    // 返回 3
        System.out.println(LRUCatchDemo.map.keySet());
        System.out.println(LRUCatchDemo.get(4));    // 返回 4
    


4.测试结果:

以上是关于手写Redis淘汰策略中lru算法(删除最近未使用的值) java版的主要内容,如果未能解决你的问题,请参考以下文章

redis前传自己手写一个LRU策略 | redis淘汰策略

redis前传自己手写一个LRU策略 | redis淘汰策略

redis前传自己手写一个LRU策略 | redis淘汰策略

redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU代码实现?

手写Redis之LRU淘汰算法

字节二面,让手写一个LFU缓存策略算法,当场我不干了!