146. LRU 缓存 && 带TTL的LRU缓存实现(拓展)

LRU缓存

方法一:手动实现双向链表 + 哈希表

cpp 复制代码
struct Node{
    int val;
    int key;
    Node* prev;
    Node* next;
    Node(int a, int b): key(a), val(b), prev(nullptr), next(nullptr) {}
    Node():key(0), val(0), prev(nullptr), next(nullptr) {}
};
class LRUCache {
private:
    Node* removeTail() {
        Node* node = tail->prev;
        removeNode(node);
        return node;
    }

    void removeNode(Node* node) {
        node->next->prev = node->prev;
        node->prev->next = node->next;
    }

    void addToHead(Node* node) {
        node->next = head->next;
        node->prev = head;
        head->next = node;
        node->next->prev = node;
    }
public:
    unordered_map<int, Node*> cache;
    int size;
    int capacity;
    Node* head;
    Node* tail;
    LRUCache(int capacity) {
        this->capacity = capacity;
        size = 0;
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
    }
    
    int get(int key) {
        if(!cache.count(key)) {
            return -1;
        }
        Node* node = cache[key];
        removeNode(node);
        addToHead(node);
        return node->val;
    }
    
    void put(int key, int value) {
        if(!cache.count(key)) {
            Node* node = new Node(key, value);
            addToHead(node);
            ++size;
            cache[key] = node;
            if(size > capacity) {
                Node* removed = removeTail();
                cache.erase(removed->key);
                --size;
                delete removed;
            }
        } else {
            Node* node = cache[key];
            node->val = value;
            removeNode(node);
            addToHead(node);
        }
    }
};

拓展

实现带TTL的LRU缓存
要求 :

在本题的基础上,为 key 增加过期时间(put 调用时额外传入过期时间)。如果 key 过期,则需要删除掉。

cpp 复制代码
#include <unordered_map>
#include <chrono>

using namespace std;
using namespace std::chrono;

struct Node {
    int val;
    int key;
    Node* prev;
    Node* next;
    time_point<steady_clock> timestamp; // 时间戳,记录节点插入或更新时间

    Node(int a, int b) : key(a), val(b), prev(nullptr), next(nullptr) {
        timestamp = steady_clock::now(); // 初始化时间戳
    }

    Node() : key(0), val(0), prev(nullptr), next(nullptr) {
        timestamp = steady_clock::now(); // 初始化时间戳
    }
};

class LRUCache {
private:
    Node* removeTail() {
        Node* node = tail->prev;
        removeNode(node);
        return node;
    }

    void removeNode(Node* node) {
        node->next->prev = node->prev;
        node->prev->next = node->next;
    }

    void addToHead(Node* node) {
        node->next = head->next;
        node->prev = head;
        head->next = node;
        node->next->prev = node;
    }

    bool isExpired(Node* node, int ttl) {
        auto now = steady_clock::now();
        auto duration = duration_cast<milliseconds>(now - node->timestamp).count();
        return duration > ttl; // 如果超过TTL,则认为已过期
    }

public:
    unordered_map<int, Node*> cache;
    int size;
    int capacity;
    int ttl; // TTL时间,单位为毫秒
    Node* head;
    Node* tail;

    LRUCache(int capacity, int ttl) : capacity(capacity), ttl(ttl) {
        size = 0;
        head = new Node();
        tail = new Node();
        head->next = tail;
        tail->prev = head;
    }

    int get(int key) {
        if (!cache.count(key)) {
            return -1;
        }
        Node* node = cache[key];

        // 检查是否过期
        if (isExpired(node, ttl)) {
            removeNode(node);
            cache.erase(key);
            --size;
            delete node;
            return -1;
        }

        // 更新节点时间戳
        node->timestamp = steady_clock::now();
        removeNode(node);
        addToHead(node);
        return node->val;
    }

    void put(int key, int value) {
        if (!cache.count(key)) {
            Node* node = new Node(key, value);

            // 如果缓存已满,移除最久未使用的节点
            if (size >= capacity) {
                Node* removed = removeTail();
                cache.erase(removed->key);
                --size;
                delete removed;
            }

            // 插入新节点
            addToHead(node);
            cache[key] = node;
            ++size;
        } else {
            Node* node = cache[key];
            node->val = value;

            // 检查是否过期
            if (isExpired(node, ttl)) {
                removeNode(node);
                cache.erase(key);
                --size;
                delete node;
                put(key, value); // 重新插入
                return;
            }

            // 更新节点时间戳
            node->timestamp = steady_clock::now();
            removeNode(node);
            addToHead(node);
        }
    }
};

总结 :

在原代码基础上为每一个steady_lock的timestamp时间戳, 每次get或者put已有Node时进行检测isExpired,如果检测已经过期则对get删除节点, 对put更新时间戳

相关推荐
Eloudy2 小时前
简明量子态密度矩阵理论知识点总结
算法·量子力学
点云SLAM2 小时前
Eigen 中矩阵的拼接(Concatenation)与 分块(Block Access)操作使用详解和示例演示
人工智能·线性代数·算法·矩阵·eigen数学工具库·矩阵分块操作·矩阵拼接操作
算法_小学生3 小时前
支持向量机(SVM)完整解析:原理 + 推导 + 核方法 + 实战
算法·机器学习·支持向量机
找不到、了4 小时前
Redis内存使用耗尽情况分析
数据库·redis·缓存
iamlujingtao4 小时前
js多边形算法:获取多边形中心点,且必定在多边形内部
javascript·算法
算法_小学生4 小时前
逻辑回归(Logistic Regression)详解:从原理到实战一站式掌握
算法·机器学习·逻辑回归
DebugKitty4 小时前
C语言14-指针4-二维数组传参、指针数组传参、viod*指针
c语言·开发语言·算法·指针传参·void指针·数组指针传参
qystca5 小时前
MC0241防火墙
算法
hzk的学习笔记5 小时前
Redis的事务和Lua之间的区别
数据库·redis·缓存
行然梦实7 小时前
粒子群优化算法(Particle Swarm Optimization, PSO) 求解二维 Rastrigin 函数最小值问题
算法·机器学习·数学建模