博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
左神算法进阶班6_1LFU缓存实现
阅读量:4541 次
发布时间:2019-06-08

本文共 5469 字,大约阅读时间需要 18 分钟。

【题目】

LFU也是一个著名的缓存算法,自行了解之后实现LFU中的set 和 get

要求:两个方法的时间复杂度都为O(1)

【题解】

LFU算法与LRU算法很像

但LRU是最新使用的排在使用频率最前面,也就是LRU是通过使用时间进行排序,

使用时间越新,其使用频率越高,而使用时间越久,其使用频率越低,即当空间满时,被删除的概率最大

而LFU是根据使用次数来算使用频率的,使用次数越多,其使用频率越高,使用次数越少,使用频率越低,当空间满时越容易被删除

同样,使用hash_map表和双向链表进行存储;

hash表存储关键词与双向链表的节点地址

而双向链表的数据存储的是使用次数,每种使用次数仍然是一个双向链表,

当put一个数据,则在使用次数为1的链表节点下的链表中按put顺序依次存储

当每get一个数据,若存在,而在相对应使用次数的链表节点中拿出,放在下一个链表节点下,即使用次数 + 1的节点

记住,在相同的使用次数中,是按照使用时间顺序进行存放的,

所以,当空间满时,首先删除大链表的头中的头,即使用次数为1的节点中的头结点【最早放入】,若使用次数都一样,同样是删除该使用次数节点中链表的 头节点

所以,数据存放于链表尾部,数据删除于链表的头部

还有,当某个链表节点为空,则删除,某个链表节点不存在,则新建

比如,当使用次数为2的节点中无数据,则删出该节点,

当有一个新数据的使用次数为2时,发现不存在使用次数为2的节点,那么就应该新建一个节点

 

【代码】

  

1 #pragma once  2 #include 
3 #include
4 5 using namespace std; 6 7 struct Node//子链表 8 { 9 int key; 10 int val; 11 int num; 12 Node* next; 13 Node* pre; 14 Node(int a, int b, int n) :key(a), val(b), num(n), next(nullptr), pre(nullptr) {} 15 }; 16 17 struct NodeList//主链表 18 { 19 int num; 20 Node* head;//子链表的头节点 21 Node* tail;//子链表的尾结点 22 NodeList* next; 23 NodeList* pre; 24 NodeList(int a) :num(a), next(nullptr), pre(nullptr) 25 { 26 head = new Node(0, 0, a);//新建一个子链表的头结点 27 tail = head; 28 } 29 }; 30 31 class LFU 32 { 33 public: 34 LFU(int size) :capacity(size) {} 35 void set(int key, int value); 36 int get(int key); 37 38 private: 39 void getNode(Node*& p, NodeList*& h);//将节点从子链表中取出 40 void moveNode(Node*& p, NodeList*& h);//将节点向后移动 41 void deleteNode(int num, NodeList*& h);//删除子链表 42 void createNode(Node*p, NodeList*& h);//新建子链表,并插入在主链中 43 void updataNode(Node*& p, NodeList*& h);//更新函数的使用次数 44 void deleteData();//容量不足需要删除 45 46 private: 47 int capacity; 48 NodeList* headList = new NodeList(0);//主链表的头结点 49 hash_map
dataMap;//key <——> 真实数据节点地址 50 hash_map
headMap;//次数 <——> 链表头节点地址 51 }; 52 53 void LFU::set(int key, int value) 54 { 55 if (this->capacity == 0) 56 return; 57 if (dataMap.find(key) != dataMap.end())//已经存在 58 { 59 Node* p = dataMap[key];//找到数据节点 60 NodeList* h = headMap[p->num];//找到头链表节点 61 p->val = value; 62 63 updataNode(p, h);//更新数据的使用次数 64 } 65 else//如果不存在,则新建 66 { 67 if (dataMap.size() >= this->capacity)//容量不足,需要删除数据 68 deleteData(); 69 70 Node* p = new Node(key, value, 1);//使用用一次 71 dataMap[key] = p;//记录 72 73 //将新建节点插入使用1次的子链表中 74 if (headMap.find(1) == headMap.end())//当使用1次的子链表不存在 75 createNode(p, headList); 76 else 77 moveNode(p, headMap[1]);//插入在使用次数在1的子链表中 78 } 79 } 80 81 int LFU::get(int key) 82 { 83 if (dataMap.find(key) == dataMap.end())//数据不存在 84 return -1; 85 Node* p = dataMap[key];//找到数据节点 86 NodeList* h = headMap[p->num]; 87 updataNode(p, h); 88 89 return p->val; 90 } 91 92 void LFU::getNode(Node*& p, NodeList*& h)//将节点从子链表中取出 93 { 94 p->pre->next = p->next; 95 if (p->next == nullptr) 96 h->tail = p->pre; 97 else 98 p->next->pre = p->pre; 99 }100 101 void LFU::moveNode(Node*& p, NodeList*& q)//将节点向后移动102 {103 p->next = q->tail->next;104 q->tail->next = p;105 p->pre = q->tail;106 q->tail = p;107 }108 109 void LFU::deleteNode(int num, NodeList*& h)//删除子链表110 {111 headMap.erase(num);//从map中删除112 h->pre->next = h->next;113 if (h->next != nullptr)114 h->next->pre = h->pre;115 delete h;116 h = nullptr;117 }118 119 120 void LFU::createNode(Node*p, NodeList*& h)//新建子链表,并插入在主链中121 {122 NodeList* q = new NodeList(p->num);//新建一个子链表123 headMap[p->num] = q;//保存对应的地址124 125 moveNode(p, q);////将节点放入子链表中 126 127 //将新子链插入主链表中128 q->next = h->next;129 if (h->next != nullptr)130 h->next->pre = q;131 h->next = q;132 q->pre = h;133 }134 135 void LFU::updataNode(Node*& p, NodeList*& h)//更新函数的使用次数136 {137 int num = p->num;138 p->num++;//使用次数+1139 140 //将p从子链表中取出141 getNode(p, h);142 143 //将该数据向后面移动144 if (headMap.find(p->num) == headMap.end())//不存在num+1的节点,那么新建145 createNode(p, h);146 else147 moveNode(p, headMap[p->num]);////将节点放入子链表中 148 149 //如果该子链表为空,将该子链表删除,并从map中删除150 if (h->head == h->tail)151 deleteNode(num, h);152 }153 154 void LFU::deleteData()//容量不足需要删除155 {156 NodeList* p = headList->next;157 Node* q = p->head->next;//删除子链表排在最前面的数据158 if (q == p->tail)//要删除的数据就是最后一个数据,则删除该节点和子链表159 deleteNode(q->num, p);160 else161 {162 p->head->next = q->next;163 q->next->pre = p->head;164 }165 dataMap.erase(q->key);//删除记录166 delete q;//删除167 q = nullptr;168 }169 170 171 void Test()172 {173 LFU* f = new LFU(3);174 f->set(1, 11);175 f->set(2, 22);176 f->set(3, 33);177 cout << f->get(4) << endl;178 f->set(4, 44);179 cout << f->get(1) << endl;180 cout << f->get(2) << endl;181 cout << f->get(2) << endl;182 cout << f->get(2) << endl;183 cout << f->get(3) << endl;184 cout << f->get(3) << endl;185 cout << f->get(4) << endl;186 cout << f->get(4) << endl;187 cout << f->get(4) << endl;188 f->set(5, 55);189 cout << f->get(3) << endl;190 cout << f->get(5) << endl;191 192 }

 

转载于:https://www.cnblogs.com/zzw1024/p/11080778.html

你可能感兴趣的文章
三次握手和四次挥手(二)
查看>>
MySQL中的索引
查看>>
Android开发之手势滑动(滑动手势监听)详解
查看>>
switch
查看>>
HTTP错误code大全
查看>>
PAT Advanced Level 1043
查看>>
决策树基础
查看>>
献给程序员之如何与陌生人交谈
查看>>
Python之登录接口
查看>>
【arc074E】RGB Sequence
查看>>
工作3年了才开始有自己的积累
查看>>
使用axios向后端传递数据,后端接收不到?
查看>>
List 去处自定义重复对象方法
查看>>
CoreData的使用-1
查看>>
阿里云安装samba
查看>>
mybatis + log4j 打印mybatis的sql
查看>>
解决Visual Studio:"无法导入以下密钥文件: xxxx.pfx,该密钥文件可能受密码保护"
查看>>
[NOI2013]矩阵游戏
查看>>
转:不规则按钮实现
查看>>
poj 3744 Scout YYF I (矩阵快速幂)
查看>>