在LeetCode的题目中,考察list操作的比较少,所以这道题也算是经典了,只有17%的通过率也足以说明问题。STL的list模板是一个环形双链表,其支持链表的基本操作,并且封装了reverse、sort、merge、splice等算法,为链表的操作提供许多遍历,这篇博客会根据在STL源码分析中的内容进行简单介绍。
题目
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations:
getandput.
get(key)– Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(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.Follow up:
Could you do both operations in O(1) time complexity?
Example:
LRUCache cache = new LRUCache( 2 /* capacity */ ); cache.put(1, 1); cache.put(2, 2); cache.get(1); // returns 1 cache.put(3, 3); // evicts key 2 cache.get(2); // returns -1 (not found) cache.put(4, 4); // evicts key 1 cache.get(1); // returns -1 (not found) cache.get(3); // returns 3 cache.get(4); // returns 4
分析
这道题目,没做对很大程度上是因为没有理解题意。题目要求要求每次删除最久没有操作过的删去。于是这就是一个队列,每次操作了哪个元素,就将那个元素提到队列最前,每次删除时删除队尾就可以了。至于O(1)操作时间,则完全可以借助Hash表来实现。
链表
STL的LIST是一个环状的双向链表。关于LIST的实现,最好参考STL源码分析来理解。这里介绍list中封装的几个方法:splice、sort。还有一个merge算法,merge的输入要求连个链表都是排序好的。
void sort():容器内所有元素排序,默认是升序
template<class Pred>void sort(Pred pr):容器内所有元素根据预断定函数pr排序
void swap(list& str):两list容器交换功能
void unique():容器内相邻元素若有重复的,则仅保留一个
void splice(iterator it,list& li):队列合并函数,队列li所有函数插入迭代指针it前,x变成空队列
void splice(iterator it,list& li,iterator first):队列li中移走[first,end)间元素插入迭代指针it前
void splice(iterator it,list& li,iterator first,iterator last):x中移走[first,last)间元素插入迭代器指针it前
void reverse():反转容器中元素顺序
代码
class LRUCache {
using ListIt = list<pair<int, int>>::iterator;
public:
LRUCache(int capacity) {
size = capacity;
}
int get(int key) {
auto it = hash.find(key);
if (it == hash.end()){
return -1;
}
cache.splice(cache.begin(), cache, it->second); // 将一个元素提前
return it->second->second;
}
void put(int key, int value) {
auto it = hash.find(key);
if (it != hash.end()){
it->second->second = value;
return cache.splice(cache.begin(), cache, it->second);
}
cache.insert(cache.begin(), {key, value});
hash[key] = cache.begin();
if (cache.size() > size){
hash.erase(cache.back().first);
cache.pop_back();
}
}
private:
unordered_map<int, ListIt> hash;
list<pair<int, int>> cache;
int size;
};