[Leetcode] LRU Cache. 哈希表+双向链表之实现
2015-12-12 14:45
337 查看
题目
首先来看题目,就是实现一个LRU,最近最少使用。Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
思路
get()相当于读,
set()即是写。一次读或写意味着对缓存块使用了一次,该缓存的优先级就提高。
思路比较简单,基于哈希表和双向链表。先通过哈希表查找缓存块的位置,也就是缓存块在链表中的位置。然后把该缓存块置于链表表头。如果缓存已经满了,那就把表尾的缓存块丢掉,再在表头插入新的缓存块。
实现
用C++11实现的时候比较蛋疼,怪自己不够熟悉STL。这里用到连个容器:
std::list,相当于双向链表。
splice(),
push_front(),
pop_back()的复杂度为O(1)。
std::unordered_map,相当于哈希表。
find(),
insert(),
erase()的复杂度为O(1)(单个element)。
这里需要注意的地方有两点:
1. 由于这里用了
std::list,所以就不能用指针指向list中的element,要用iterator。值得注意的是,
std::list的iterator是不会因为插入删除而改变所指向的element的,而
std::vector的iterator是会改变所指向的element的(例如
erase了之后)。
所以在此哈希表可以这样实现:
unordered_map<int, list<T>::iterator> cacheMap;
2.
std::list中,element的移动可以用
splice()来实现:
例如:
std::list<int> list = {1,2,3}; auto it = list.begin(); it = std::next(it); //it指向第二个element,2 if (it != list.begin()) { // 将list.begin()置于it之后 list.splice(list.begin(), list, it, std::next(it)); // 2,1,3 }
My Solution
/* * LRUCache * * Using double linked list (stl list) and hash map(stl unordered_map) */ #include <iostream> #include <unordered_map> #include <memory> #include <list> using namespace std; struct KeyVal { int key; int value; }; class LRUCache{ private: int capacity; // cache capacity list<KeyVal> cache; // cache, implement in Double-Linked-List unordered_map<int, list<KeyVal>::iterator> cacheMap; // Hash Map, quickly access to value public: LRUCache(int capacity): capacity(capacity) { } int get(int key) { auto it = cacheMap.find(key); // Find by key if (it != cacheMap.end()) { //Find it! Get the value. auto kv = it->second; // Move to front if (kv != cache.begin()) cache.splice(cache.begin(), cache, kv, next(kv)); return kv->value; } return -1; } void set(int key, int value) { auto it = cacheMap.find(key); // Find by key if (it != cacheMap.end() ){ // find and set new value auto kv = it->second; kv->value = value; // move front if (kv != cache.begin()) cache.splice(cache.begin(), cache, kv, next(kv)); } else { // Not found if (cacheMap.size() < capacity) { KeyVal newKv = {key, value}; // set in cache cache.push_front(newKv); // add to map cacheMap.insert(make_pair(key, cache.begin())); }else { // Capacity is not enough // Delete the least used value int oldKey = cache.back().key; cache.pop_back(); cacheMap.erase(oldKey); // Add new value KeyVal newKv = {key, value}; cache.push_front(newKv); cacheMap.insert(make_pair(key, cache.begin())); } b5ed } } };
相关文章推荐
- 一步一步跟我学易语言之第二个易程序菜单设计
- C#数据结构之顺序表(SeqList)实例详解
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 基于逻辑运算的简单权限系统(原理,设计,实现) VBS 版
- C#中设计、使用Fluent API
- 数据结构之Treap详解
- 基于逻辑运算的简单权限系统(原理,设计,实现) VBS 版
- C#数据结构之堆栈(Stack)实例详解
- C#数据结构之双向链表(DbLinkList)实例详解
- JavaScript数据结构和算法之图和图算法
- JavaScript 组件之旅(一)分析和设计
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- C# 事件的设计与使用深入理解
- 大型网站设计注意事项大全
- Android中的脑残设计总结
- Java数据结构及算法实例:插入排序 Insertion Sort