LRUCache往往用于排列最近被”修改或访问过的热门的“数据,属缓存类目,是我个人认为链表系中,和跳表共同组成链表系的两个最大的实体
其组成,就是一个双向链表,同时有一个hash表实现快速的由key找到对应节点,当有读取操作时,如果能够找到对应key的节点,不仅符合节点value,还会把该key对应节点放在链表头部位置,当修改或插入操作时,如hash表可以找到该key的节点即update,并不是仅更新value这样,而是先删除该节点,然后创建一个新的节点并放在头部,插入也是会将新创建的节点作为链表头,体现了最新被操作的key的数据总是被更新在链表头部。
LRUCache自定义链表的容量限制,当插入新节点时发现已满,则要删除尾部节点,再创建新节点并置于头部,意味着代码需要维护tail节点。
LRUCache往往实践中被用于缓存,是一个重要的数据结构。
代码:
#include <iostream>
#include <unordered_map>
template<class T> struct Node {
T key;
T val;
Node<T> *next;
Node<T> *prev;
Node(T _key, T _val):key(_key), val(_val), next(nullptr), prev(nullptr) {}
};
template<class T> class LruCache {
Node<T> *head;
Node<T> *tail;
int size;
int maxsize;
std::unordered_map<T, Node<T> *> nodemap;
void Insert (T key, T val) {
Node<T> *newnode = new Node<T>(key, val);
if (!head) {
head = newnode;
tail = newnode;
head->next = tail->next = nullptr;
head->prev = tail->prev = nullptr;
return;
}
newnode->next = head;
newnode->prev = head->prev;
head->prev = newnode;
head = newnode;
nodemap[key] = newnode;
}
void Delete (Node<T> *node) {
if (node) {
Node<T> *prev = node->prev;
Node<T> *next = node->next;
if (prev) {
prev->next = next;
}
if (next) {
next->prev = prev;
}
if (node == tail) {
tail = prev;
}
nodemap.erase(node->key);
delete node;
node = nullptr;
}
}
public:
LruCache (int _maxsize):size(0), maxsize(_maxsize), head(nullptr), tail(nullptr) {}
~LruCache () {
Node<T> *cur = head;
while (cur) {
Node<T> *next = cur->next;
delete cur;
cur = next;
}
size = 0;
nodemap.clear();
}
void Set (T key, T val) {
if (nodemap.find(key) == nodemap.end()) {
if (size < maxsize) {
Insert(key, val);
++size;
} else {
Delete(tail);
Insert(key, val);
}
} else {
Node<T> *node = nodemap.find(key)->second;
Delete(node);
Insert(key, val);
}
}
bool Get (T key, T &val) {
if (nodemap.find(key) != nodemap.end()) {
Node<T> *node = nodemap.find(key)->second;
val = node->val;
Delete(node);
Insert(key, val);
return true;
}
return false;
}
void Show () {
Node<T> *cur = head;
while (cur) {
std::cout << cur->key << "\t";
cur = cur->next;
}
std::cout << std::endl;
}
};
int main () {
LruCache<int> lrc(20);
for (int i = 0; i < 100; i++) {
lrc.Set(i, i);
lrc.Show();
int v;
lrc.Get(i - 1, v);
lrc.Show();
}
return 0;
}