手写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.测试结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值