CodeTop之LRU缓存

题目链接

146. LRU 缓存 - 力扣(LeetCode)

题目解析

算法原理

我们使用双向链表+哈希表的形式来模拟缓存机制

首先我们要自己实现一个双链表, 自己写一个内部类, 这个内部类记录了key,value,prev,next(前驱和后继), 后续我们就通过这个内部类来构造双向链表

其次我们要把LRU缓存机制和我们的双向链表联系起来

我们每次查找一个Key所对应的value, 如果存在的话, 那么就相当于这个key-value组合是常常访问的, 因此我们要把它的优先级提高, 具体的代码就是我们把这个key-value的结点放在双向链表的头部,如果头插后,我们的缓存大小超过了指定大小, 那么就尾删

hash<Integer,DoubleLinkde>, 存key和key-value组成的双链表的结点, DoubleLinkde是我们自定义的内部类来模拟双链表

我们每次查找一个key, 如果在hash表里面能够找到, 那么就把这个结点移动到头部(头插),如果插进去超过大小了, 就尾删, 越靠近后面,访问频次越低.

双链表能够存贮前驱和后继的值, 这样可以很方便进行头插和尾删

代码编写

class LRUCache {
    private int capacity;// 设置的缓存大小
    private int currentSize;// 当前缓存的大小
    private HashMap<Integer, DoubleLinked> map;// 用哈希表存储key-value
    private DoubleLinked head, tail;// 虚拟头尾结点

    // 双向链表节点类
    private class DoubleLinked {
        int key, value;
        DoubleLinked prev, next;
    // 构造方法
        public DoubleLinked() {}
        public DoubleLinked(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    // 构造函数,初始化容量
    public LRUCache(int capacity) {
        this.capacity = capacity;
        this.currentSize = 0;
        map = new HashMap<>();
        
        // 初始化伪头节点和伪尾节点
        head = new DoubleLinked();
        tail = new DoubleLinked();
        head.next = tail;
        tail.prev = head;
    }

    // 获取缓存中的值,如果存在返回值,否则返回-1
    public int get(int key) {
        DoubleLinked node = map.get(key);
        if (node == null) {
            return -1;
        }
        // 访问过该节点,移动到头部
        moveToHead(node);
        return node.value;
    }

    // 插入一个新的键值对
    public void put(int key, int value) {
        DoubleLinked node = map.get(key);

        if (node == null) {
            // 插入新节点
            DoubleLinked newNode = new DoubleLinked(key, value);
            map.put(key, newNode);
            addToHead(newNode);
            currentSize++;

            if (currentSize > capacity) {
                // 超过容量,移除尾部节点
                DoubleLinked tailNode = removeTail();
                map.remove(tailNode.key);
                currentSize--;
            }
        } else {
            // 更新已有节点的值,并移动到头部
            node.value = value;
            moveToHead(node);
        }
    }

    // 将节点添加到头部
    private void addToHead(DoubleLinked node) {
        node.next = head.next;
        node.prev = head;
        head.next.prev = node;
        head.next = node;
    }

    // 将节点移到头部
    private void moveToHead(DoubleLinked node) {
        if (node == null) {
            return;
        }
        removeNode(node);
        addToHead(node);
    }

    // 移除节点
    private void removeNode(DoubleLinked node) {
        if (node == null) {
            return;
        }
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    // 移除尾部节点
    private DoubleLinked removeTail() {
        if (tail.prev == null) {
            return null;
        }
        DoubleLinked node = tail.prev;
        removeNode(node);
        return node;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值