LRU算法的实现

  • 分析
    LeetCode 146就是实现一个LRU算法,LRU算法的原理不再记录。LRU算法的实现的核心数据结构是哈希链表,就是双向链表和哈希表的结合体。LRU算法需要满足下面3个条件。1)cache中的元素必须是有时序的,以区分最近使用的和久未使用的数据,当容量满之后要删除最久未使用的那个元素腾出位置 ;2)我们要在cache中快速找某个key是否存在并得到value;3) 每次访问cache中的某个key,需要将这个元素变为最近使用的,也就是说cache要支持在任意位置快速插入和删除元素。哈希链表可以满足各种要求。需要思考的是为什么使用双向链表?为什么在哈希表中存了key还要在链表中存储?这两个问题在代码注释中进行了解释。
  • 代码
class node{
public:
    int key,val;
    node* prev;
    node* next;
    node(int key, int val) : key(key), val(val), prev(nullptr), next(nullptr){}
};

class List{
private:
    node* head;
    node* tail;
    int size;
public:
    List(){
        head = new node(0, 0);
        tail = new node(0, 0);
        head -> next = tail;
        tail -> prev = head;
        size = 0;
    }        

    //在链表尾部添加节点x
    void addNode(node* x){
        x -> prev = tail -> prev;
        x -> next = tail;
        tail -> prev -> next = x;
        tail -> prev = x;
        size++;
    }

    //删除链表中的x节点(x一定存在)
    void delNode(node* x){//因为要删除结点,所以需要使用双链表,已达到节省时间的目的
        x -> prev -> next = x -> next;
        x -> next -> prev = x -> prev;
        size--;
    }

    //删除链表中的第一个节点,并返回该节点,时间复杂度O(1)
    node* removeFirst(){
        if(head -> next == tail) return nullptr;

        node* temp = head -> next;
        delNode(temp);
        return temp;
    }

    int getsize(){ 
        return this -> size; 
    }
};

class LRUCache {
private:
    unordered_map<int, node*> map;
    List cache;
    int cap;    
public:
    LRUCache(int capacity) {
        cap = capacity;
    }
    
    int get(int key) {
        
        if(map.find(key) == map.end()) return -1;
        makeRecently(key);
        return map[key] -> val;        
    }
    
    void put(int key, int value) {
        if(map.find(key) != map.end()){
        //key已存在
            delKey(key);
            addRecently(key, value);
            return;
        }

        if(cap == cache.getsize()){
            //删除最久未使用的元素
            removeLeastRecently();
        }
        addRecently(key, value);
    }
    //将某个key提升为最近使用
    void makeRecently(int key){
        node* x = map[key];
        cache.delNode(x);
        cache.addNode(x);
    }

    //添加最近使用的元素
    void addRecently(int key, int val){
        node* x = new node(key, val);

        cache.addNode(x);
        map[key] = x;
    }

    //删除某一个key
    void delKey(int key){
        node* x = map[key];

        cache.delNode(x);
        map.erase(key);
    }

    //删除最久未使用的元素
    void removeLeastRecently(){
    //链表头部的第一个元素就是最久未使用的
        node* x = cache.removeFirst();
        int deleteKey = x -> key;

    //就是因为要删除map中的key,所以才必须在双链表中同时存储key和val
        map.erase(deleteKey);
    }
};
上一篇:leetcode 146 LRU 缓存机制


下一篇:mysql简单操作一