1、描述
实现一个lru缓存机制算法。
查询复杂度O(1),删除添加复杂度也是O(1)
题目描述
2、关键字
lru
3、思路
使用一个hash表,把当前的键,和键+值,搞成一个哈希映射表,然后通过链表的方式把历史数据存起来。使用头插法,维护最近使用的元素在链表头。
4、notes
把链表,双向链表的定义分离,代码结构清晰。
5、复杂度
时间O(1)
空间O(1)
6、code
struct Node{ // 直接双向链表的一个节点,双向链表的初始化工作在LRU类的构造函数中
int key;
int val;
Node * left;
Node * right;
Node(int k, int v):key(k),val(v),left(nullptr),right(nullptr){}
}*L,*R; // 直接声明两个两端的节点:head和tail
void remove(Node * p){ // 双向链表可以直接删除自己
p->right->left = p->left;
p->left->right = p->right;
}
void insert(Node *p){ // 头插法
p->right = L->right; // 自己八字一撇
p->left = L; // 自己八字一捺,一朵花
L->right->left = p;
L->right = p;
}
class LRUCache {
public:
int n; // 容量
unordered_map<int,Node *> mp; // 链表的哈希表
LRUCache(int capacity) { // 初始化LRU类 : 容量,双向链表,
n = capacity;
L = new Node(-1,-1); // 以下4行初始化双向链表
R = new Node(-1,-1);
L->right = R;
R->left = L;
}
int get(int key) { // 获取这个键对应的值
if(mp.count(key) == 0) return -1; // 先检查有没有,如果没有直接返回
remove(mp[key]);// 有,先移除,在从头部添加进来
insert(mp[key]);
return mp[key]->val;
}
void put(int key, int value) { // 添加
if(mp.count(key)){ // 如果存在,就更新,调整一下在链表中的位置
auto p = mp[key];
p->val = value;
remove(p);
insert(p);
}
else{ // 不存在
if(mp.size() == n){ // 满了
auto p = R->left; // 删除最后一个元素
remove(p);
mp.erase(p->key);
delete p; // 可写可不写
//auto node = new Node(key,value); // 放到后面一起写
//insert(node);
}
auto node = new Node(key,value); // 添加
mp[key] = node;
insert(node);
}
}
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
第二个:key和value都是string的时候:
再写一个测试案例:
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
struct Node{
string key;
string val;
Node * left;
Node * right;
Node(string k,string v) : key(k),val(v),left(nullptr),right(nullptr){}
}*L,*R;
void remove(Node * p){
p->right->left = p->left;
p->left->right = p->right;
}
void insert(Node * p){
p->right= L->right;
p->left = L;
L->right->left = p;
L->right = p;
}
class LRUCache{
public:
int n;
unordered_map<string,Node*>mp;
LRUCache(int max_size){
n = max_size;
L = new Node (" "," ");
R = new Node(" "," ");
L->right = R;
R->left = L;
}
string get(string key){
if(mp.count(key) == 0) return "";
remove(mp[key]);
insert(mp[key]);
return mp[key]->val;
}
void set(string key,string value){
if(mp.count(key)){
auto p = mp[key];
p->val = value;
remove(p);
insert(p);
}
else{
if((int)mp.size() == n){
auto p = R->left;
remove(p);
mp.erase(p->key);
delete p;
}
auto node = new Node(key,value);
mp[key] = node;
insert(node);
}
}
void del(string key){
if(mp.count(key)){
auto p = mp[key];
remove(p);
auto node = new Node("","");
mp[key] = node;
}
}
};
int main(){
auto cache = new LRUCache(5);
string s2 = "abc",s3 = "ABC",S4 = "aaa",S5 = "AAA";
cache->set(s2,s3); // 1
cache->set("qqq","QQQ"); // 2
cache->set("aaa","AAA"); // 3
cache->set("bbb","BBB"); // 4
string S3 = cache->get("abc");
cache->set("ccc","CCC"); // 5
cache->set("ddd","DDD"); // 6
s2 = "abc";
string S2 = cache->get(s2);
cout<<S2<<endl;
cache->set("eee","EEE"); // 7
cache->set("fff","FFF"); // 8
cache->set("ggg","GGG"); // 9
string s1 = cache->get(s2);
return 0;
}
如下,是进行了封装,显得更加的专业
链接
public class LRUCache {
HashMap<Integer, Node> map;
DoubleLinkedList cache;
int cap;
public LRUCache(int capacity){
map = new HashMap<>();
cache = new DoubleLinkedList();
cap = capacity;
}
public void put(int key, int val){
Node newNode = new Node(key, val);
if(map.containsKey(key)){
cache.delete(map.get(key));
cache.addFirst(newNode);
map.put(key, newNode);
}else{
if(map.size() == cap){
int k = cache.deleteLast();
map.remove(k);
}
cache.addFirst(newNode);
map.put(key, newNode);
}
}
public int get(int key){
if(!map.containsKey(key)) return -1;
int val = map.get(key).val;
put(key, val);
return val;
}
}
/**
* head: recently used
* tail: LRU
*/
class DoubleLinkedList{
Node head;
Node tail;
public DoubleLinkedList(){
head = new Node(0,0);
tail = new Node(0,0);
head.next = tail;
tail.prev = head;
}
public void addFirst(Node node){
node.next = head.next;
node.prev = head;
head.next.prev = node;
head.next = node;
}
public int delete(Node n){
int key = n.key;
n.next.prev = n.prev;
n.prev.next = n.next;
return key;
}
public int deleteLast(){
if(head.next == tail) return -1;
return delete(tail.prev);
}
}
class Node{
public int key;
public int val;
public Node prev;
public Node next;
public Node(int key, int val){
this.key = key;
this.val = val;
}
}