题目来自lintcode134
为最近最少使用(Least Recently Used,LRU)缓存策略设计一个数据结构,它应该支
持以下操作:获取数据和写入数据。
² get(key) 获取数据:如果缓存中存在 key,则获取其数据值(通常是正数),否则返回
-1。
² set(key, value) 写入数据:如果 key 还没有在缓存中,则写入其数据值。当缓存达到上
限,它应该在写入新数据之前删除最近最少使用的数据用来腾出空闲位置。
最终, 你需要返回每次 get 的数据。
整体上最大的难点就是无法用同一个数据结构完成查找和顺序的组织两大核心功能,既然如此,就使用两个数据结构完成,利用哈希查找的优势,辅以逻辑增删(物理删除是浪费时间的很大一个部分),加上使用双向链表便捷地操作元素的顺序,给出最远未使用的元素,整体上极大地加快了速度,当然代码行数也增加了一倍。
教训:
- LRU删除时删除的时最远未使用的,和最少没关系,题目表述有问题。
- 欲利用哈希查找快的优点,就要接受其无序或者说组织顺序比较困难的缺点,而欲利用链表顺序组织方便快捷的优点,就要接收它难以查找的缺点,程序员做的事情就是综合长处,精巧
#include<iostream>
#include<unordered_map>
using namespace std;
struct group {
int val;
int key;
group* leftlink;
group* rightlink;
group(int value, int k_) {
val = value;
key = k_;
leftlink = nullptr;
rightlink = nullptr;
}
};
class LRUCache {
private:
group* use_head;
group* use_tail;
unordered_map<int, pair<bool, group*>> useage;
int upline;
int now;
public:
/*
* @param capacity: An integer
*/LRUCache(int capacity) {
upline = capacity;
now = 0;
use_head = nullptr;
use_tail = nullptr;
}
/*
* @param key: An integer
* @return: An integer
*/
int get(int key) {
if (useage.find(key) == useage.end() || useage.find(key)->second.first == false) {
return -1;
}
else {
group* temp = useage.find(key)->second.second;
if (temp->leftlink==nullptr&&temp->rightlink!=nullptr ) {
temp->rightlink->leftlink = nullptr;
use_head = temp->rightlink;
temp->leftlink = use_tail;
temp->rightlink = nullptr;
use_tail->rightlink = temp;
use_tail = temp;
}
else if (temp == use_tail||(temp->leftlink==nullptr&&temp->rightlink==nullptr)) {
}
else {
temp->leftlink->rightlink = temp->rightlink;
temp->rightlink->leftlink = temp->leftlink;
temp->leftlink = use_tail;
temp->rightlink = nullptr;
use_tail->rightlink = temp;
use_tail = temp;
}
return use_tail->val;
}
}
/*
* @param key: An integer
* @param value: An integer
* @return: nothing
*/
void set(int key, int value){
if (useage.find(key) == useage.end() || useage.find(key)->second.first == false) {
if (now < upline)
{
//connect temp with tail node drictly
group* temp = new group(value, key);
//if linklist is empty , the first is head and tail
if (use_head == nullptr) {
use_head = temp;
use_tail = temp;
}
else {
use_tail->rightlink = temp;
temp->leftlink = use_tail;
use_tail = temp;
}
if (useage.find(key)== useage.end()) {
useage.insert({ key,{ true,temp } });
}
else {
useage.find(key)->second.first = true;
}
now++;
}
else {
//delete first node
useage.find(use_head->key)->second.first = false;
if (use_head->rightlink == nullptr){
delete use_head;
use_head = nullptr;
}
else {
use_head = use_head->rightlink;
delete use_head->leftlink;
use_head->leftlink = nullptr;
}
//connect temp with tail node
group* temp = new group(value, key);
use_tail->rightlink = temp;
temp->leftlink = use_tail;
use_tail = temp;
if (useage.find(key) == useage.end()) {
useage.insert({ key,{ true,temp } });
}
else {
useage.find(key)->second.first = true;
useage.find(key)->second.second = use_tail;
}
}
}
else {
useage.find(key)->second.second->val = value;
//ensure this node at the tail of whole linklist
group* temp = useage.find(key)->second.second;
if (temp != use_tail&&temp!=use_head) {
temp->leftlink->rightlink = temp->rightlink;
temp->rightlink->leftlink = temp->leftlink;
temp->leftlink = use_tail;
temp->rightlink = nullptr;
use_tail->rightlink = temp;
use_tail = temp;
}
else if (temp == use_head&&temp!= use_tail) {
temp->rightlink->leftlink = nullptr;
use_head = temp->rightlink;
temp->leftlink = use_tail;
temp->rightlink = nullptr;
use_tail->rightlink = temp;
use_tail = temp;
}
}
}
};