微软面试题: LeetCode 146. LRU 缓存机制 middle 出现次数:3
实现一个 LRUCache
类:使得 put 和 get 操作都达到 O(1)
哈希表 + 双向队列
双向队列 中存储 缓存(页面)信息,使用哈希表可以实现O(1) 找到 缓存的位置,使用双向队列可以 实现O(1)
时间的从头部插入(更新刚用过的页为最新状态)和从尾部删除(淘汰最近最久未使用的页)。
直接上代码:
1 struct Node 2 { 3 int key; 4 int value; 5 Node(int k,int v):key(k),value(v){} 6 }; 7 class LRUCache { 8 public: 9 LRUCache(int capacity):buff_size(capacity) {} 10 11 int get(int key) 12 { 13 // get 操作 缺页,直接返回 -1 14 if(hash_table.find(key) == hash_table.end()) 15 { 16 return -1; 17 } 18 // 借助哈希表O(1)实现 get操作 19 int value = hash_table[key]->value; 20 // 刷新当前页为最新 21 put( key, value); 22 // Cache.splice(Cache.begin(), Cache,hash_table[key]); 23 return value; 24 } 25 26 void put(int key, int value) 27 { 28 //未命中且Cache已满,淘汰最近最久未使用页, 29 if(hash_table.find(key) == hash_table.end() && Cache.size() == buff_size) 30 { 31 int key = Cache.back().key; 32 Cache.pop_back();//淘汰最近最久未使用页 33 hash_table.erase(key);//同时删除hash表中对应的记录 34 } 35 //命中 删除掉Cache中目标记录,此时hash表可不更新,因为该页马上就要再插入Cache 36 if(hash_table.find(key) != hash_table.end()) 37 { 38 Cache.erase(hash_table[key]); 39 } 40 //将当前页面重新插入到Cache 头部,同时更新hash表记录当前页最新位置 41 Node node(key,value); 42 Cache.push_front(node); 43 hash_table[key] = Cache.begin(); 44 return; 45 } 46 private: 47 int buff_size; 48 list<Node> Cache; 49 unordered_map<int,list<Node>::iterator> hash_table; 50 }; 51 52 /** 53 * Your LRUCache object will be instantiated and called as such: 54 * LRUCache* obj = new LRUCache(capacity); 55 * int param_1 = obj->get(key); 56 * obj->put(key,value); 57 */
使用 list 的splice 函数 ,可以提高效率 ,代码如下:
1 struct Node 2 { 3 int key; 4 int value; 5 Node(int k,int v):key(k),value(v){} 6 }; 7 class LRUCache { 8 public: 9 LRUCache(int capacity):buff_size(capacity) {} 10 11 int get(int key) 12 { 13 // get 操作 缺页,直接返回 -1 14 if(hash_table.find(key) == hash_table.end()) 15 { 16 return -1; 17 } 18 // 借助哈希表O(1)实现 get操作 19 int value = hash_table[key]->value; 20 // 刷新当前页为最新 21 //put( key, value); 22 Cache.splice(Cache.begin(), Cache,hash_table[key]); 23 return value; 24 } 25 26 void put(int key, int value) 27 { 28 //命中 删除掉Cache中目标记录,此时hash表可不更新,因为该页马上就要再插入Cache 29 if(hash_table.find(key) != hash_table.end()) 30 { 31 hash_table[key]->value = value; 32 return Cache.splice(Cache.begin(), Cache,hash_table[key]); 33 } 34 //将当前页面重新插入到Cache 头部,同时更新hash表记录当前页最新位置 35 Node node(key,value); 36 Cache.push_front(node); 37 hash_table[key] = Cache.begin(); 38 if(Cache.size() > buff_size) 39 { 40 hash_table.erase(Cache.back().key); 41 Cache.pop_back(); 42 } 43 return; 44 } 45 private: 46 int buff_size; 47 list<Node> Cache; 48 unordered_map<int,list<Node>::iterator> hash_table; 49 }; 50 51 /** 52 * Your LRUCache object will be instantiated and called as such: 53 * LRUCache* obj = new LRUCache(capacity); 54 * int param_1 = obj->get(key); 55 * obj->put(key,value); 56 */