剑指 Offer II 031. 最近最少使用缓存

该文章介绍了一个LRU缓存的实现,使用双向链表存储数据节点,并通过哈希表快速定位节点。链表中的节点包含键值对,头节点和尾节点用于管理链表。LRU缓存提供了get和put操作,get操作会将访问的节点移到链表尾部,put操作则会更新或新增节点至链表尾,并在超出容量时删除最不常使用的头部节点。
摘要由CSDN通过智能技术生成

在这里插入图片描述
思路:
    这里等于是构建一个双向链表,链表的值的部分是一个哈希表,他的作用是可以使用哈希表很快的找到链表的指定节点。
(1)构建链表

class DLinkNode {
public:
    int key, value;
    DLinkNode* prev, * next;
    DLinkNode() : key(0), value(0), prev(nullptr), next(nullptr) {}
    DLinkNode(int _key, int _value) : key(_key), value(_value), prev(nullptr), next(nullptr) {}
};

(2)初始化参数
    用capacity去保存容量,size去控制每次加入后的容量。head和tail是用来控制链表的头尾,head始终指向头,tail始终指向末尾。

int size, capacity;
DLinkNode* head, * tail;
unordered_map<int, DLinkNode*> hash;

(3)初始化链表

LRUCache(int capacity) :
    size(0), capacity(capacity)
{
    // 初始化双向链表
    head = new DLinkNode();
    tail = new DLinkNode();
    head->next = tail;
    tail->prev = head;
}

(4)两个操作
    第一个操作是get一个key,返回它的值。第二个操作是put,修改对应key的值,如果不存在就new一个,如果超过上限就去掉第一个(使用率最低的)。所以我们对链表有以下操作
    ①删除某个位置的节点。 void deleteNode(int key)
    ②末尾添加一个节点。 void add2Tail(int key)
    ③超过上限的时候,删除第一个节点。void deleteHead()

    操作的时候,先理清楚逻辑:

    get():判断是否已经有这个值,如果有这个值,就返回对应的value,并且将这个节点移动到最后。

int get(int key) {
    // 若不存在 key
    if (hash.count(key) == 0) {
        return -1;
                  }
    move2Tail(key); // 最近访问的 key 挪到链尾
    return hash[key]->value;
}

    put():如果存在key就修改值,同时移动,这里和put差不多。如果不存在就new一个新节点,并且插入链尾,size++,如果size超过了capacity就删除链头节点。

void put(int key, int value) {
    // 若已存在 key
    if (hash.count(key) != 0) {
        // 修改已有 key 所对应的 value
        hash[key]->value = value;
        move2Tail(key); // 挪到链尾
        return;
    }
    // 若不存在则 new
    DLinkNode* newNode = new DLinkNode(key, value);
    hash[key] = newNode;
    // 插入链尾
    add2Tail(key);
    size++;
    // 若超出规定容量                                                                                           
    if (size > capacity) {
        deleteHead();
        size--;
    }
}

(5)对链表进行操作

void deleteNode(int key) {
    // key 的前驱 next 指向 key 的后继  
    hash[key]->prev->next = hash[key]->next;
    // key 的后继 prev 指向 key 的前驱 
    hash[key]->next->prev = hash[key]->prev;
}

void add2Tail(int key) {
    // tail 的前驱 next 指向 key   
    tail->prev->next = hash[key];
    // key 的 prev 指向 tail 的前驱
    hash[key]->prev = tail->prev;
    // tail 的 prev 指向 key
    tail->prev = hash[key];
    // key 的 next 指向 tail
    hash[key]->next = tail;
}
void move2Tail(int key) {
    deleteNode(key);
    add2Tail(key);
}

void deleteHead() {
    DLinkNode* deleted = head->next;
    // head 的 next 指向 head 的后继 next
    head->next = deleted->next;
    // head 后继的 prev 指向 head
    deleted->next->prev = head;
    // 同时也从 hash 中注销
    hash.erase(deleted->key);
    delete deleted;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值