Desh

缓存管理算法LRU/LFU C++实现

Cache缓存管理算法:

详见 计组——彻底搞懂cache主存映射cache容量及cache写策略_vavid的专栏-CSDN博客_cache容量

LRU-Least  Recently Used

最常用的缓存管理算法,目标时间复杂度,查询=O(1),添加=O(1); 

实现方式:unordered_map<int,list<pair<int,int>>::iterator>M保存节点指针;List模拟缓存序列;

 1 class LRUCache {
 2 private:
 3 int cap;
 4 unordered_map<int,list<pair<int,int>>::iterator>M;
 5 list<pair<int,int>>L;
 6 public:
 7     LRUCache(int capacity) {
 8         cap=capacity;
 9     }
10     
11     int get(int key) {
12         auto p=M.find(key);
13         if(p==M.end()){
14             return -1;
15         }else{
16             L.splice(L.begin(),L,p->second);
17             auto x=M[key];
18             return x->second;
19         }
20     }
21     
22     void put(int key, int value) {
23         auto p=M.find(key);
24         if(p==M.end()){
25             L.push_front(make_pair(key,value));
26             M.insert(make_pair(key,L.begin()));
27             if(L.size()>cap){
28                 auto x=& L.back();
29                 M.erase(x->first);
30                 L.pop_back();
31             }
32         }else{
33             p->second->second=value;
34             L.splice(L.begin(),L,p->second);
35         }
36         return;
37     }
38 };

stl::list::splice()函数声明方式:

void splice(iterator position, list<T,Allocator>& x);  
void splice(iterator position, list<T,Allocator>& x, iterator it);
void splice(iterator position, list<T,Allocator>& x, iterator first, iterator last);

实现方式参考:https://blog.csdn.net/Wchenchen0/article/details/83058928

可以理解为earse+insert:

 1 class LRUCache {
 2 private:
 3 unordered_map<int,list<pair<int,int>>::iterator>M;
 4 list<pair<int,int>>L;
 5 int cap;
 6 public:
 7     LRUCache(int capacity) {
 8         this->cap=capacity;
 9     }
10     
11     int get(int key) {
12         auto p=M.find(key);
13         if(p==M.end()){
14             return -1;
15         }else{
16             L.push_front(*M[key]);
17             L.erase(M[key]);18             M[key]=L.begin();
19             return L.begin()->second;
20         }
21         return -1;
22     }
23     
24     void put(int key, int value) {
25         auto p=M.find(key);
26         if(p==M.end()){
27             if(L.size()>=cap){
28                 M.erase(L.back().first);
29                 L.pop_back();
30             }
31         }else{
32             L.erase(M[key]);
33         }
34         L.push_front(make_pair(key,value));
35         M[key]=L.begin();
36         return;
37     }
38 };

LFU-Least Frequently Used

不常见的缓存管理算法,对新数据不友好,目标时间复杂度:查询=O(1),添加=O(1); 

使用尽量清晰的存储结构,4种Map,分别以key,key出现频率为键,提供映射;其中unordered_map<int,list<int>>Freqlists存储的是相同出现频次的key链表,unordered_map<int,list<int>::iterator>Freq存储的是不同key的迭代器,即节点指针;注意Freq存放的迭代器指针指向的list节点与FreqLists并无对应分组关系。

关键条件:Freqlist刷新条件,最低使用频率key所在链表为空时,更新最小频次MinFreq

 1 class LFUCache {
 2 private:
 3 unordered_map<int,list<int>::iterator>Freq;//key->key lists iter
 4 unordered_map<int,list<int>>FreqLists;//freq->key lists 
 5 unordered_map<int,int>K;//key->freq
 6 unordered_map<int,int>M;//key->value
 7 int MinFreq=0;
 8 int cap;
 9 public:
10     LFUCache(int capacity) {
11         this->cap=capacity;
12     }
13     
14     int get(int key) {
15         auto p=M.find(key);
16         if(p==M.end()){
17             return -1;
18         }else{
19             FreqLists[K[key]].erase(Freq[key]);
20             if(FreqLists[MinFreq].size()==0)MinFreq++;// update 1
21             K[key]++;
22             FreqLists[K[key]].push_front(key);
23             Freq[key]=FreqLists[K[key]].begin();
24             return M[key];
25         }
26         return -1;
27     }
28     
29     void put(int key, int value) {
30         if(cap<=0)return;
31         auto p=M.find(key);
32         if(p==M.end()){
33             if(M.size()==cap){
34                 K.erase(FreqLists[MinFreq].back());
35                 M.erase(FreqLists[MinFreq].back());
36                 FreqLists[MinFreq].pop_back();
37             }
38             MinFreq=1;
39             M[key]=value;
40             K[key]=MinFreq;
41             FreqLists[MinFreq].push_front(key);
42             Freq[key]=FreqLists[MinFreq].begin();
43         }else{
44             M[key]=value;
45             FreqLists[K[key]].erase(Freq[key]);
46             if(FreqLists[MinFreq].size()==0)MinFreq++;// update 2
47             K[key]++;
48             FreqLists[K[key]].push_front(key);
49             Freq[key]=FreqLists[K[key]].begin();
50         }
51         return;
52     }
53 };

两大类缓存管理算法需要注意的点是先从List中更新目标节点位置,再根据新节点位置更新Map,否则会造成Map迭代器指向未分配节点地址。

posted on 2022-01-12 20:50  Desh  阅读(333)  评论(0编辑  收藏  举报

导航