LRU算法学习

1 篇文章 0 订阅

LRU算法学习

概念

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。

Demo示例

参考了尚硅谷阳哥的视频、力扣算法LRU 缓存

package com.lly.lru;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 最近最少使用算法学习
 * LRU(Least Recently Used)
 *
 *
 * @Author lyluo
 * @Date 2021/1/25
 */
public class MyLRU {

    /**
     * 定义节点
     * @param <K> 键类型
     * @param <V> 值类型
     */
    static final class Node<K, V> {
        /**
         * 键
         */
        private K key;
        /**
         * 值
         */
        private V value;
        /**
         * 上一个节点
         */
        private Node<K, V> prev;
        /**
         * 下一个节点
         */
        private Node<K, V> next;

        /**
         * 空参构造函数
         */
        public Node() {
            // 新建的节点,上一个节点,下一个节点都为空,(还没放入队列,所以前后赋值为空)
            this.prev = this.next = null;
        }

        /**
         * 带参构造函数
         * @param key
         * @param value
         */
        public Node(K key, V value) {
            this.key = key;
            this.value = value;
            this.prev = this.next = null;
        }

    }

    /**
     * 定义链表
     * @param <K> 键类型
     * @param <V> 值类型
     */
    static final class DoubleLinkedList<K, V> {
        /**
         * 队列里面的头结点
         */
        private Node<K, V> head;
        /**
         * 队列里面的尾节点
         */
        private Node<K, V> tail;

        /**
         * 构建空队列
         */
        public DoubleLinkedList() {
            // 创建头结点(虚拟节点)
            this.head = new Node<>();
            // 创建尾节点(虚拟节点)
            this.tail = new Node<>();

            // 构建指向关系,形成双向队列
            this.head.next = tail;// 头指向尾
            this.tail.prev = head;// 尾指向头
        }

        /**
         * 添加节点到队列中(从左边进行插入)
         * @param node
         */
        public void addHead(Node<K, V> node) {
            // 构建节点的指向关系
            node.next = head.next;
            node.prev = head;
            // 改变头节点的指向关系
            this.head.next.prev = node;
            this.head.next = node;
        }

        /**
         * 从队列中删除(出队列)
         * @param node
         */
        public void remove(Node<K, V> node) {
            // 重新构建指向关系
            node.next.prev = node.prev;
            node.prev.next = node.next;

            // 清空引用,便于及时GC
            node.next = null;
            node.prev = null;
        }

        /**
         * 获取最后一个节点
         * @return
         */
        public Node<K, V> getLast() {
            // 尾节点的上一个节点为最后一个节点
            return tail.prev;
        }

    }

    /**
     * 双向链表
     */
    private DoubleLinkedList<Integer, Integer> list;
    /**
     * 缓存map
     */
    private Map<Integer, Node<Integer, Integer>> cache;
    /**
     * 容量
     */
    private int capacity;
    private static final Lock lock = new ReentrantLock();

    public MyLRU(int capacity) {
        // 初始化
        list = new DoubleLinkedList<>();
        cache = new HashMap<>();
        this.capacity = capacity;
    }

    /**
     * 获取value
     * @param key
     * @return
     */
    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }

        lock.lock();
        try {
            Node<Integer, Integer> node = cache.get(key);
            list.remove(node);
            list.addHead(node);
            return node.value;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 如果key已经存在就修改,否则新增
     * @param key
     * @param value
     */
    public void put(int key, int value) {
        lock.lock();
        try {
            if (cache.containsKey(key)) {
                Node<Integer, Integer> node = cache.get(key);
                node.value = value;
                cache.put(key, node);
                list.remove(node);
                list.addHead(node);
                return;
            }

            if (cache.size() == this.capacity) {
                Node<Integer, Integer> last = list.getLast();
                cache.remove(last.key);
                list.remove(last);
            }

            Node<Integer, Integer> newNode = new Node(key, value);
            cache.put(key, newNode);
            list.addHead(newNode);
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        MyLRU cache = new MyLRU( 2 /* 缓存容量 */ );
        cache.put(1, 1);
        cache.put(2, 2);
        System.out.println(cache.get(1));// 返回  1
        cache.put(3, 3);// 该操作会使得密钥 2 作废
        System.out.println(cache.get(2));// 返回 -1 (未找到)
        cache.put(4, 4);// 该操作会使得密钥 1 作废
        System.out.println(cache.get(1));// 返回 -1 (未找到)
        System.out.println(cache.get(3));// 返回  3
        System.out.println(cache.get(4));;// 返回  4
    }

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值