146. LRU Cache
来源:互联网 发布:ansys软件报价 编辑:程序博客网 时间:2024/04/29 20:41
题目大意:设计一个用于LRU cache算法的数据结构。关于LRU的基本知识可参考here
分析:为了保持cache的性能,使查找,插入,删除都有较高的性能,我们使用双向链表(std::list)和哈希表(std::unordered_map)作为cache的数据结构,因为:
- 双向链表插入删除效率高(单向链表插入和删除时,还要查找节点的前节点)
- 哈希表保存每个节点的地址,可以基本保证在O(1)时间内查找节点
具体实现细节:
- 越靠近链表头部,表示节点上次访问距离现在时间越短,尾部的节点表示很长时间已经没被访问了
- 查询或者访问节点时,如果节点存在,把该节点弄到链表头部,同时更新hash表中该节点的地址
- 插入节点时,如果cache的size达到了上限,则删除尾部节点,同时要在hash表中删除对应的项。新节点则插入链表头部
struct CacheNode{ int key; int value; CacheNode(int k, int v):key(k), value(v){}};class LRUCache{public: LRUCache(int capacity) { size = capacity; } int get(int key) { if(cacheMap.find(key) == cacheMap.end()) return -1; else { //把当前访问的节点移到链表头部,并且更新map中该节点的地址 cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]); cacheMap[key] = cacheList.begin(); return cacheMap[key]->value; } } void set(int key, int value) { if(cacheMap.find(key) == cacheMap.end()) { if(cacheList.size() == size) {//删除链表尾部节点(最少访问的节点) cacheMap.erase(cacheList.back().key); cacheList.pop_back(); } //插入新节点到链表头部,并且更新map中增加该节点 cacheList.push_front(CacheNode(key, value)); cacheMap[key] = cacheList.begin(); } else {//更新节点的值,把当前访问的节点移到链表头部,并且更新map中该节点的地址 cacheMap[key]->value = value; cacheList.splice(cacheList.begin(), cacheList, cacheMap[key]); cacheMap[key] = cacheList.begin(); } }private: list<CacheNode> cacheList; unordered_map<int, list<CacheNode>::iterator>cacheMap; int size;};2015.9.20更新
----------------
思路:
LRU cache数据结构的核心就是当存储空间满了,而有新的item要插入时,要先丢弃最早的item。这里的数据结构需要符合以下条件:
1. 要能快速找到最早更新的item。这里需要将item以更新时间顺序排序。
可选的有:queue(队列),heap(优先级队列),linked list(链表)
2. 要能快速访问指定item,并且访问以后要更新它的时间顺序。
对于更新时间顺序这个操作,queue和heap要做到就很困难了。所以这点最佳的是linked list。但linked list中查找指定item需要遍历,这里可以用一个hash table来记录key与节点之间的对应。并且由于要随时更新节点位置,doubly linked list更为适用。
1. 要能快速找到最早更新的item。这里需要将item以更新时间顺序排序。
可选的有:queue(队列),heap(优先级队列),linked list(链表)
2. 要能快速访问指定item,并且访问以后要更新它的时间顺序。
对于更新时间顺序这个操作,queue和heap要做到就很困难了。所以这点最佳的是linked list。但linked list中查找指定item需要遍历,这里可以用一个hash table来记录key与节点之间的对应。并且由于要随时更新节点位置,doubly linked list更为适用。
还有一点需要注意的是,当把一个新元素A插入到list前面的时候,我们在unordered_map中保存新元素A对应的iterator(也就是list.begin())。当继续插入其他元素B,C,D进入list前面时,unordered_map中保存的A元素对应的iterator并没有失效!!!切记!
代码如下:class LRUCache{private: struct cacheNode { int key; int value; cacheNode(int k, int v): key(k), value(v) {} }; unordered_map<int, list<cacheNode>::iterator> uMap; list<cacheNode> lst; int cap;public: LRUCache(int capacity) { cap = capacity; } int get(int key) { if (uMap.count(key)==0) { return -1; } else { lst.splice(lst.begin(), lst, uMap[key]); uMap[key] = lst.begin(); return uMap[key]->value; } } void set(int key, int value) { if (uMap.count(key)) { lst.splice(lst.begin(), lst, uMap[key]); uMap[key] = lst.begin(); uMap[key]->value = value; } else { if (uMap.size()==cap) { uMap.erase(lst.back().key); lst.pop_back(); lst.push_front(cacheNode(key, value)); uMap[key] = lst.begin(); } else { lst.push_front(cacheNode(key, value)); uMap[key] = lst.begin(); } } }};
0 0
- LeetCode 146. LRU Cache
- [leetcode] 146.LRU Cache
- 146. LRU Cache
- leetcode 146. LRU Cache
- Leetcode 146. LRU Cache
- Leetcode - 146. LRU Cache
- Leetcode 146. LRU Cache
- [leetcode] 146. LRU Cache
- Leetcode 146. LRU Cache
- leetcode 146. LRU Cache
- LeetCode-146. LRU Cache
- LeetCode 146. LRU Cache
- 146. LRU Cache
- LeetCode 146. LRU Cache
- 146. LRU Cache
- 146. LRU Cache
- 146. LRU Cache
- 146. LRU Cache
- JAVA控制语句
- [LeetCode] Permutation Sequence
- struts2-ajax-页面的自动刷新
- 使用ngrok作为外网映射工具
- Memcahce和Redis比较
- 146. LRU Cache
- gdoi 8.20模拟总结
- java date20150820
- 近几天小结
- 归并排序
- 欢迎使用CSDN-markdown编辑器
- java date20150819
- JAVA基本数据类型
- 日志处理(文件的读出和写入)