当前位置:   article > 正文

经典面试题:实现LRU页面置换算法_lru经典例题

lru经典例题

问题描述

146. LRU为例,题目如下:
在这里插入图片描述


思路

可以定义链表节点对应缓冲块,这样就可以用双向链表保存当前的缓存块,每次加入、更新或查找缓存块都会使对应节点移动至链表头,每次需要替换出缓存块时将链尾节点(最久未使用)移除,使用链表的好处是定位到对应节点后,再进行插入或删除操作的时间复杂度都是 O ( 1 ) O(1) O(1)的,但定位链表节点就比较慢,所有可以使用哈希表记录缓存块的键对应的链表节点,这样定位链表节点的时间复杂度就是近似 O ( 1 ) O(1) O(1)的。在操作过程我们维护哈希表和链表(链表头尾节点),这样就可以实现O(1)的平均时间复杂度的 g e t get get p u t put put方法。实现过程中可以封装两个基本的方法:1) e m p l a c e _ f r o n t emplace\_front emplace_front: 将新节点插入链表头同时更新哈希表, 2) u p d a t e update update: 更新或访问链表中的节点:先将原节点从链表中删除,再将新节点插入链表头,同时更新哈希表node。


实现代码

版本1. 自定义链表节点实现

双向链表节点类:

class Node {
public:
    int k, v;//键,值
    Node *prev, *next;//前驱节点,后继节点

    Node(int key = -1, int val = -1, Node *prev_ = nullptr, Node *next_ = nullptr) : k(key), v(val), prev(prev_), next(next_) {}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

LRU实现:

class LRUCache {
public:
    LRUCache(int capacity) {
        n = capacity;
        cnt = 0;
        head = new Node();
        tail = head;
    }

    int get(int key) {
        if (!node.count(key))
            return -1;
        update(key);
        return node[key]->v;
    }

    void put(int key, int value) {
        if (node.count(key)) {
            update(key, value);
            return;
        }
        if (cnt++ == n) {
            cnt--;
            node.erase(tail->k);
            Node *tail0 = tail;
            tail = tail->prev;
            tail->next = nullptr;
            delete tail0;
        }
        emplace_front(key, value);
    }

private:
    int n;
    Node *head, *tail;//链表头尾节点
    unordered_map<int, Node *> node;//键到链表节点的映射
    int cnt;//节点数

    void emplace_front(int key, int value) {//将(key,value)插入链表头, 同时更新哈希表node
        Node *t = new Node(key, value, head, head->next);
        if (head == tail)//可能需要更新tail节点
            tail = t;
        if (head->next)
            head->next->prev = t;
        head->next = t;
        node[key] = t;//更新哈希表
    }

    void update(int key, int val = -1) {//更新或访问(key,val): 先将(key,val)从链表中删除, 再将新的(key,val)插入链表头, 同时更新哈希表node
        Node *x = node[key];
        if (val != -1)//更新val
            x->v = val;
        if (x == tail)
            tail = tail->prev;
        x->prev->next = x->next;
        if (x->next)
            x->next->prev = x->prev;
        emplace_front(x->k, x->v);
        delete x;
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

版本2. list迭代器模拟链表节点实现

使用list同时用list的迭代器模拟链表节点,这样的好处就是不用手动维护链表的尾节点,同时list有 e m p l a c e _ f r o n t emplace\_front emplace_front p o p _ b a c k pop\_back pop_back等方法,就不用再去实现一遍,所有通过list迭代器模拟链表节点来实现比自定义链表节点实现会更简洁一些。

class LRUCache {
public:
    LRUCache(int capacity) {
        n = capacity;
    }

    int get(int key) {
        if (!node.count(key))
            return -1;
        update(key);
        return node[key]->second;
    }

    void put(int key, int value) {
        if (node.count(key)) {
            update(key, value);
            return;
        }
        if (li.size() == n) {
            node.erase(li.rbegin()->first);
            li.pop_back();
        }
        li.emplace_front(key, value);
        node[key] = li.begin();
    }

private:
    int n;
    list<pair<int, int>> li;//链表
    unordered_map<int, list<pair<int, int>>::iterator> node;//键到链表节点的映射

    void update(int key, int val = -1) {//更新或访问(key,val): 先将(key,val)从链表中删除, 再将新的(key,val)插入链表头, 同时更新哈希表node
        auto x = *node[key];
        if (val != -1)
            x.second = val;
        li.erase(node[key]);
        li.push_front(x);
        node[key] = li.begin();
    }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/519392
推荐阅读
相关标签
  

闽ICP备14008679号