https://leetcode-cn.com/problems/lru-cache/
// 头文件
class LRUCache
{
public:
LRUCache(int capacity);
int get(int key);
void put(int key, int value);
private:
std::unordered_map<int, std::list<std::pair<int, int>>::iterator> table;
std::list<std::pair<int, int>> lru;
int capacity;
};
// https://leetcode-cn.com/problems/lru-cache/
// https://labuladong.gitbook.io/algo/shu-ju-jie-gou-xi-lie/lru-suan-fa
// 哈希表 + 双向链表
LRUCache::LRUCache(int capacity)
{
this->capacity = capacity;
}
// std::unordered_map<int, std::list<std::pair<int, int>>::iterator> table;
// std::list<std::pair<int, int>> lru;
int LRUCache::get(int key)
{
auto it = table.find(key); // std::list<std::pair<int, int>>::iterator 为啥不是这个类型?
if (it != table.end())
{
lru.splice(lru.begin(), lru, it->second);// 找到了,将这个放在链表最前面
return it->second->second;
}
return -1;
}
void LRUCache::put(int key, int value)
{
auto it = table.find(key);
if (it != table.end())
{
lru.splice(lru.begin(), lru, it->second); // 如果找到了就更新这个值
it->second->second = value;
return;
}
lru.emplace_front(key, value);
table[key] = lru.begin();
if (table.size() > capacity) // 取size不要用list::size() 在C++里这个方法可能不是O(1)的
{
table.erase(lru.back().first);
lru.pop_back();
}
}
list::splice的用法和 emplace
/*
list::splice实现list拼接的功能。将源list的内容部分或全部元素删除,拼插入到目的list。
函数有以下三种声明:
一:void splice ( iterator position, list<T,Allocator>& x );
二:void splice ( iterator position, list<T,Allocator>& x, iterator it );
三:void splice ( iterator position, list<T,Allocator>& x, iterator first, iterator last );
解释:
position 是要操作的list对象的迭代器
list&x 被剪的对象
对于一:会在position后把list&x所有的元素到剪接到要操作的list对象(会将x全部裁切到list中,并且清空x,在position之前)
对于二:只会把it的值剪接到要操作的list对象中(只裁切一个元素)
对于三:把first 到 last 剪接到要操作的list对象中(裁切一个范围。x里需要被移动的元素的迭代器。区间为[first, last).)
*/
void splice()
{
std::list<int> list1;
std::list<int> list2 = { 10, 20 };
std::list<int>::iterator it;
for (int i = 1; i < 4; ++i)
{
list1.push_back(i); // 1 2 3
}
it = list1.begin();
++it; // point to 2
list1.splice(it, list2); // 将list2的元素插入到it前面,清空list2的元素
printList(list1); // 1 10 20 2 3
printList(list2); // empty
#ifdef ALLOW_PRINT
std::cout << *it << std::endl; // 2 还指向这个元素
#endif
list2.splice(list2.begin(), list1, it);
printList(list1); // 1 10 20 3
printList(list2); // 2
// 此时it迭代器失效了???但是还能打印值
#ifdef ALLOW_PRINT
std::cout << *it << std::endl; // 2
#endif
it = list1.begin();
advance(it, 2); // 迭代器递增函数,it指向20
list1.splice(list1.begin(), list1, it, list1.end());
printList(list1); // 20 3 1 10
it = list1.begin();
advance(it, 2); // it指向1
std::list<int>::iterator it2 = list2.end();
list2.splice(list2.end(), list1, it, list1.end()); // 插入的位置可以是end()迭代器
printList(list1); // 20 3
printList(list2); // 2 1 10
}
// 当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。
// 而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造元素。
// emplace相关函数可以减少内存拷贝和移动。当插入rvalue,它节约了一次move构造,当插入lvalue,它节约了一次copy构造。
void emplace()
{
std::list<int> list1 = { 1, 2, 3, 4, 5 };
list1.emplace(list1.begin(), 222);
printList(list1); // 222 1 2 3 4 5
list1.emplace_back(333);
printList(list1); // 222 1 2 3 4 5 333
list1.emplace_front(111);
printList(list1); // 111 222 1 2 3 4 5 333
}