LRU Cache(双向循环链表加hashmap)

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

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(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.

Follow up:
Could you do both operations in O(1) time complexity?

Example:

LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4
/* 链表 + hashmap
 *
 * 在链表头部插入新节点, 在链表尾部删除节点
 * 查找: 利用hashmap 把key映射为 Node*
 *
 * get: 在map中查找, 不存在, 返回-1
 *      存在, 则删除这个节点,并移动到链表头部
 *
 * put: 若key在map中存在: 删除该节点, 插入在头部
 *      否则:新建节点并插入 若此时达到容量上限再删除链表尾部
 *
 * 频繁的用到删除这个元素的操作: 如果知道前驱的位置 很好删除, 但是不知道,解决方法:
 *    (1) 使用双向链表
 *    (2) 设删除的是cur, 交换cur, curnext的值, 然后删除curnext.
 *
 * 具体到链表 可以用自己实现的双向链表 也可以用stl中list(double)
 * 此处用自己定义的带头结点的双向循环链表
 * */
struct Node{
    int value, key;
    Node *next, *pre;
    Node(int k, int val):key(k), value(val), next(NULL), pre(NULL){}
};
class LRUCache {
public:
    int size, count;
    Node *head = new Node(0, 0);// 头结点 head->next 指向第一个节点, head->pre 指向尾节点
    unordered_map<int, Node*> m;

    LRUCache(int capacity) {
        size = capacity;
        count = 0;
        head->next = head;
        head->pre = head;
    }

    int get(int key) {
        if(m.count(key)==0) return -1;
        // 存在, 就删除这个节点, 然后插入到头结点后面
        Node *tmp = m[key];
        delNode(tmp);
        pushHead(tmp);
        //cout<<"get and erase"<<key<<endl;
        return tmp->value;
    }

    void put(int key, int value) {
        cout<<"put "<<key<<" "<<value<<endl;
        if(m.count(key)==0){// 不存在则创建新节点, 否则只需要修改值然后放在头部
            if(count==size){//  当前表已经满 则删除最后一个元素
                //cout<<"too long and erase "<<head->pre->key<<endl;
                m.erase(head->pre->key);
                delNode(head->pre);
                count--;
            }
            count++;
            Node *tmp = new Node(key, value);
            pushHead(tmp);
            m[key]=tmp;
        }
        else{
            Node *tmp = m[key];
            tmp->value = value;
            delNode(tmp);
            //cout<<"put and erase "<<tmp->key<<endl;
            pushHead(tmp);
        }
    }

    // 在双向链表中删除节点p
    void delNode(Node *p){
        p->pre->next = p->next;
        p->next->pre = p->pre;
    }
    void pushHead(Node *p){// 头插法
       p->next = head->next;
       head->next = p;
       p->next->pre = p;
       p->pre = head;
    }
};

猜你喜欢

转载自blog.csdn.net/futangxiang4793/article/details/88953303