【LeetCode刷题记录】LRU Cache

本文介绍了LRU Cache的设计思路,包括使用双向链表保持访问顺序,以及结合哈希表提高查找效率。通过详细讲解,阐述了如何利用这两种数据结构实现一个高效的LRU Cache,并提供了C++的AC代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

解答

LRU Cache,是一种经典的Cache结构。考虑这几点:

  • 第一点:确定存储Cache元素的数据结构。Cache一般是顺序结构,在Cache的所有元素中,最近访问的应该放在前面,最久没访问的应该放在靠后的位置。如果用数组来组织,主要问题是移动cache中的某个元素位置(如插到头部或从尾部删除)时,不可避免地要改变部分或全部元素的位置,代价太大。如果用单链表来组织,移动元素位置只需要改变链表节点的next指针。但在把最近访问的元素插到头部,或者从尾部删除最久没有访问的元素时,需要从前往后遍历链表,来确定被操作节点的前驱节点的位置,详细解释可参考LRU cache implementation - Is a double linked list necessary ? 。因此,最终确定用来存放cache数据的结构是双向链表,它很好地解决了上面提到的两个问题。
  • 第二点:设计查找Cache元素的数据结构。众所周知,访问链表只能从前往后依次遍历。这种方式可行,但不高效。而题目中给出了元素的key和value,所以很容易联想到使用哈希表。其中,哈希表的键是元素的key,值是元素在链表中节点的地址指针。

综上所述,实现一个LRU Cache需要用到双向链表(doubly linked list)和哈希表(hash map)这两种数据结构。下面是参考如何用C++实现一个LRU Cache这篇文章完成的AC代码:

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

// define doubly linked list node
typedef struct Node {
    int key;
    int val;
    Node *previous;
    Node *next;
}Node;

class LRUCache{

public:
    LRUCache(int capacity) {
        linkedList = (Node *)malloc(sizeof(Node) * capacity);
        for (int i = 0; i < capacity; i++) {
            freeEntries.push_back(linkedList + i);
        }
        head = (Node *)malloc(sizeof(Node));
        tail = (Node *)malloc(sizeof(Node));
        head->previous = NULL;
        head->next = tail;
        tail->previous = head;
        tail->next = NULL;
    }

    int get(int key) {
        // first find the node of specified key
        Node *p =  hash[key];

        // if found, move the node into head, then return its value
        if (p) {
            // deattach the node
            p->previous->next = p->next;
            p->next->previous = p->previous;

            // insert in new position
            p->next = head->next;
            head->next->previous = p;
            p->previous = head;
            head->next = p;

            return p->val;
        }
        else { // not found
            return -1;
        }
    }

    void set(int key, int value) {
        Node *p = hash[key]; // if not found, p is ponited NULL(0x0)

        // if found, modify value, then move it to head
        if (p) {
            // deattach the node
            p->previous->next = p->next;
            p->next->previous = p->previous;

            // modify the value
            p->val = value;

            // insert in new position
            p->next = head->next;
            head->next->previous = p;
            p->previous = head;
            head->next = p;
        }
        else { // if not found, fetch a free space, then insert it into head
            if (freeEntries.empty()) { // cache is full
                p = tail->previous;

                // deattach the node
                p->previous->next = p->next;
                p->next->previous = p->previous;

                hash.erase(p->key);
            }
            else { // cache is not full
                p = freeEntries.back(); // get the last free element from free list
                freeEntries.pop_back(); // delete the last element
            }

            p->key = key;
            p->val = value;
            hash[key] = p;

            // insert the new node into head
            p->next = head->next;
            head->next->previous = p;
            p->previous = head;
            head->next = p;
        }
    }

private:
    Node *head;
    Node *tail;
    Node *linkedList;
    unordered_map<int, Node*> hash; // look up key faster
    vector<Node * > freeEntries; // store available nodes 
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值