【码不停题3.18】LRU缓存机制实现 双向链表+哈希map

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。

进阶:

你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4

#include <map>
#include <list>
class LRUCache {
private:
    unordered_map<int, list<pair<int, int>>::iterator> mp;
    list<pair<int, int>> lt;
    int size;
public:
    LRUCache(int capacity) {
        size = capacity;
    }
    
    int get(int key) {
        if (mp.count(key)) {
            int result = mp[key]->second;
            lt.splice(lt.begin(), lt, mp[key]);
            return result;
        } else {
            return -1;
        }
    }
    
    void put(int key, int value) {
        if (mp.count(key)) {
            mp[key]->second = value;
            lt.splice(lt.begin(), lt, mp[key]);
        } else {
            lt.emplace_front(key,value);
            mp[key] = lt.begin();
            if (lt.size() > size) {
                mp.erase(lt.back().first);
                lt.pop_back();
            }
        }
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

总结

  1. 对于关联容器,如map,set(以及multi类型)等,erase当前的迭代器iterator,仅仅会使当前的iterator失效,并不影响以后的内容,所以只要在进行删除前,预先保留下一个当前迭代器的递增值即可。这是因为关联类容器使用了红黑树实现,删除一个节点不会对其他节点造成影响。
    对于序列式容器,如 vector,deque等,删除当前节点会使后面的所有节点的迭代器失效。这是因为这类容器每次进行插入或者删除都会使之后的元素位置进行重新移动定位,致使之前的迭代器失效。
  2. void emplace_front (Args&&... args);
    Construct and insert element at beginning
    Inserts a new element at the beginning of the list, right before its current first element. This new element is constructed in place using args as the arguments for its construction.
    void push_front (const value_type& val);
    Inserts a new element at the beginning of the list, right before its current first element. The content of val is copied (or moved) to the inserted element.
  3. splice
    // entire list (1)	
    void splice (iterator position, list& x);
    // single element (2)	
    void splice (iterator position, list& x, iterator i);
    // element range (3)	
    void splice (iterator position, list& x, iterator first, iterator last);
    
    Transfers elements from x into the container, inserting them at position.
  4. .back()是最后一个 .end()是最后一个后的一个

猜你喜欢

转载自blog.csdn.net/MmmTHU/article/details/88648071