Skip to content

Commit 7fb3ca5

Browse files
committed
feat: add lfu cache
1 parent f789e3b commit 7fb3ca5

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

others/lfu_cache.cpp

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
#include <iostream>
2+
#include <unordered_map>
3+
4+
namespace Cache {
5+
6+
template <typename T>
7+
class D_Node {
8+
public:
9+
T data;
10+
D_Node<T> *prev;
11+
D_Node<T> *next;
12+
13+
D_Node(T data) : data(data), prev(nullptr), next(nullptr) {}
14+
};
15+
16+
template <typename K, typename V>
17+
using CacheNode = D_Node<std::pair<K, V>>;
18+
19+
template <typename K, typename V>
20+
class LFUCache {
21+
std::unordered_map<K, std::pair<CacheNode<K, V> *, int>> node_map;
22+
std::unordered_map<int, std::pair<CacheNode<K, V> *, CacheNode<K, V> *>>
23+
freq_map;
24+
25+
int minFreq;
26+
int _capacity;
27+
28+
public:
29+
LFUCache(int _capacity) : minFreq(0), _capacity(_capacity) {}
30+
31+
private:
32+
void push(int freq, CacheNode<K, V> *node) {
33+
if (!freq_map.count(key)) {
34+
freq_map[freq] = {node, node};
35+
}
36+
37+
std::pair<CacheNode<K, V> *, CacheNode<K, V> *> &p = freq_map[freq];
38+
39+
p.first->prev = node;
40+
node->next = p.first;
41+
p.first = node;
42+
}
43+
44+
void inc_freq(std::pair<CacheNode<K, V> *, int> &p_node) {
45+
CacheNode<K, V> *node = p_node.first;
46+
int freq = p_node.second;
47+
48+
std::pair<CacheNode<K, V> *, CacheNode<K, V> *> &p = freq_map[freq];
49+
50+
if (p.first == node && p.second == node) {
51+
freq_map.erase(freq);
52+
if (minFreq == freq) {
53+
minFreq = freq + 1;
54+
}
55+
} else {
56+
CacheNode<K, V> *prev = node->prev;
57+
CacheNode<K, V> *next = node->next;
58+
node->prev = nullptr;
59+
node->next = nullptr;
60+
61+
if (prev) {
62+
prev->next = next;
63+
} else {
64+
p.first = next;
65+
}
66+
67+
if (next) {
68+
next->prev = prev;
69+
} else {
70+
p.second = prev;
71+
}
72+
}
73+
push(freq + 1, node);
74+
p_node.second++;
75+
}
76+
77+
void pop() {
78+
std::pair<CacheNode<K, V> *, CacheNode<K, V> *> &p = freq_map[minFreq];
79+
if (p.first == p.second) {
80+
delete p.first;
81+
freq_map.erase(minFreq);
82+
return;
83+
}
84+
CacheNode<K, V> *temp = p.second;
85+
p.second = temp->prev;
86+
p.second->next = nullptr;
87+
delete temp;
88+
}
89+
90+
public:
91+
void put(K key, V value) {
92+
if (node_map.count(key)) {
93+
node_map[key].first->data.second = value;
94+
inc_freq(node_map[key]);
95+
return;
96+
}
97+
98+
if (node_map.size() == _capacity) {
99+
node_map.erase(freq_map[minFreq].second->data.first);
100+
pop();
101+
}
102+
CacheNode<K, V> *node = new CacheNode<K, V>({key, value});
103+
node_map[key] = {node, 1};
104+
minFreq = 1;
105+
push(1, node);
106+
}
107+
108+
V get(K key) {
109+
if (!node_map.count(key)) {
110+
throw std::exception("key is not present in the cache");
111+
}
112+
113+
V value = node_map[key].first->data.second;
114+
inc_freq(node_map[key]);
115+
return value;
116+
}
117+
118+
int size() { return node_map.size(); }
119+
120+
int capacity() { return _capacity; }
121+
122+
bool empty() { return node_map.size() == 0; }
123+
124+
~LFUCache() {
125+
auto it = node_map.begin();
126+
while (it != node_map.end()) {
127+
delete it->second.first;
128+
it++;
129+
}
130+
}
131+
};
132+
} // namespace Cache

0 commit comments

Comments
 (0)