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.
The cache is initialized with a positive capacity.
Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ );
Test case:
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
/**
* Author sesiria, 2019
* LRU Cache implementation by double linklist and unordered_map(hash table)
*/
#include <algorithm>
#include <iostream>
#include <unordered_map>
using namespace std;
class LRUCache
{
private:
struct Linklist
{
int key;
int val;
Linklist *next;
Linklist *prev;
Linklist(int k, int n) : key(k), val(n), next(nullptr), prev(nullptr) {}
};
unordered_map<int, Linklist *> table;
Linklist *head; // virtual header.
Linklist *tail; // virtual tailer node.
int theCapacity;
// private method.
void removeFromList(Linklist *node)
{
// cut the node from list
node->prev->next = node->next;
node->next->prev = node->prev;
}
void insertToHeader(Linklist *node)
{
node->next = head->next;
node->next->prev = node;
head->next = node;
node->prev = head;
}
public:
LRUCache(int capacity)
{
theCapacity = capacity;
head = new Linklist(0, 0);
tail = new Linklist(0, 0);
head->next = tail;
tail->prev = head;
}
~LRUCache()
{
delete head;
delete tail;
}
int get(int key)
{
auto iter = table.find(key);
if (iter == table.end())
return -1;
else
{
Linklist *node = iter->second;
removeFromList(node);
insertToHeader(node);
return node->val;
}
}
void put(int key, int value)
{
auto iter = table.find(key);
// the key is already existed.
if (iter != table.end())
{
Linklist *node = iter->second;
node->val = value;
removeFromList(node);
insertToHeader(node);
}
else
{
// the LRU cache is full, we remove the last element.
if (table.size() == theCapacity)
{
Linklist *node = tail->prev;
table.erase(node->key);
removeFromList(node);
delete node;
}
Linklist *newNode = new Linklist(key, value);
insertToHeader(newNode);
table.insert(make_pair(key, newNode));
}
}
};
int main()
{
LRUCache cache(2);
int result;
cache.put(1, 1);
cache.put(2, 2);
result = cache.get(1); // returns 1
cache.put(3, 3); // evicts key 2
result = cache.get(2); // returns -1 (not found)
cache.put(4, 4); // evicts key 1
result = cache.get(1); // returns -1 (not found)
result = cache.get(3); // returns 3
result = cache.get(4); // returns 4
return 0;
}
A Thread-safe LRU Cache Model by C++ Template and C++17