内存淘汰算法是一个比较重要的算法,经常会被问道:如果让你设计一个LRU算法你会怎么做?尽可能的保持存取的高效。那么就依着这道算法题对LRU进行一个简单的介绍。
题目地址:https://oj.leetcode.com/problems/lru-cache/
1.什么是LRU算法?为什么使用LRU?
LRU即Least Recently Used的缩写,即最近最少使用的意思。我们知道在内存空间是有限的,那么当内存被数据占满的时候,而需要访问的数据又不在内存中,那么就需要将内存中的最少使用的数据淘汰掉,给新加入的数据腾出空间。LRU经常在用于缓存服务器中的数据淘汰,缓存对数据的访问速度要求较高,因此要设计一个高效的算法。
2.题目的要求是这样的:
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get
and set
.
get(key)
- Get the value (will always be positive) of the key if the key exists in the cache,
otherwise return -1.
set(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.
即实现一个LRU算法,实现get和set操作。
get(key)--如果key存在于cache中,返回key对应的value值;否则返回-1。
set(key,value)--如果key不在cache中,那么插入或者设置value值。当cache达到存储空间,在插入新的值之前,要删除掉最近最少使用的元素。
3.算法设计:
注意,重要的是高效,高效,再高效。尽可能在插入和删除的时间复杂度为O(1)。那么要怎么设计数据结构才能达到?不着急,先说两个相对低效的实现方案。
3.1:纯map实现(超时)
用纯map实现,key就是key,value为一个结构体,里面放的是value以及time(time就是距离0的时间,key越不用,那么time越小)。
class LRUCache{ private: typedef struct value { int val; int times; }tValue; map<int,tValue> mkv; map<int,tValue> :: iterator it; int capacity; public: LRUCache(int capacity) { this->capacity = capacity; } int get(int key) { if( is_exist(key) ) { mkv[key].times = 0; it = mkv.begin(); while(it!=mkv.end()) { if(it->first == key) { it++; continue; } (it->second).times -= 1; it++; } return mkv[key].val; } else { return -1; } } void set(int key , int value) { if( is_exist(key) ) return ; int mint,mink; if(mkv.size()==capacity) { it = mkv.begin(); mint = (it->second).times; mink = it->first; it++; while(it!=mkv.end()) { if( (it->second).times < mint ) { mint = (it->second).times; mink = it->first; } it++; } mkv.erase(mink); } mkv[key].val = value; mkv[key].times = 0; it = mkv.begin(); while(it!=mkv.end()) { if(it->first == key) { it++; continue; } it->second.times -= 1; it++; } } bool is_exist(int key) { return ( mkv.find(key) != mkv.end() ) ; } void print() { it = mkv.begin(); while(it!=mkv.end()) { cout<<"key="<<it->first<<",value="<<it->second.val<<",times="<<it->second.times<<endl; it++; } cout<<endl; } };
class LRUCache { private: int capacity; int capacity_cur; typedef struct ListNode { int key; int value; struct ListNode* next; struct ListNode* pre; ListNode(int k , int v):key(k),value(v),next(NULL),pre(NULL) {} }ListNode; ListNode *head; typedef struct Value { int val; ListNode *p; Value(int _v,ListNode *pp):val(_v),p(pp){} Value() {} //if this constructor is not defined,there will be wrong }tValue; map< int,tValue > mkv; map< int,tValue > :: iterator it; public: LRUCache(int capacity) { this->capacity = capacity; head = new ListNode(0,0); capacity_cur = 0; } int get(int key) { if( is_exist(key) ) { //get down the loc node ListNode *loc = mkv[key].p; loc->pre->next = loc->next; loc->next->pre = loc->pre; //insert into the front of the head loc->next = head->next; loc->pre = head; head->next = loc; loc->next->pre = loc; return mkv[key].val; } else { return -1; } } void set(int key , int value) { if( is_exist(key) ) { mkv[key].val = value; ListNode *q = mkv[key].p; q->value = value; return ; } ListNode *tmp = new ListNode(key,value); if(capacity_cur<capacity) { if(head->next==NULL) //the list is empty { head->next = tmp ; head->pre = tmp; tmp->next = head; tmp->pre = head; tValue tv(value,tmp); mkv[key] = tv; ++capacity_cur; } else //insert the tmp into the front of the list { tmp->next = head->next; tmp->pre = head; head->next->pre = tmp; head->next = tmp; tValue tv(value,tmp); mkv[key] = tv; ++capacity_cur; } } else { //get rid of the lru node ListNode *tail = head->pre; head->pre = tail->pre; tail->pre->next = head; mkv.erase(tail->key); delete tail; //insert into the new node tmp->next = head->next; tmp->pre = head; head->next->pre = tmp; head->next = tmp; tValue tv(value,tmp); mkv[key] = tv; } } bool is_exist(int key) { return ( mkv.find(key) != mkv.end() ); } void print() { ListNode *p = head->next; while(p!=head) { cout<<"key = "<<p->key<<" Value = "<<p->value<<endl; p = p->next; } cout<<endl; } };
class LRUCache { private: int capacity; int capacity_cur; typedef struct ListNode { int key; int value; struct ListNode* next; struct ListNode* pre; ListNode(int k , int v):key(k),value(v),next(NULL),pre(NULL) {} }ListNode; ListNode *head; typedef struct Value { int val; ListNode *p; Value(int _v,ListNode *pp):val(_v),p(pp){} Value() {} //if this constructor is not defined,there will be wrong }tValue; map< int,tValue > mkv; map< int,tValue > :: iterator it; public: LRUCache(int capacity) { this->capacity = capacity; head = new ListNode(0,0); capacity_cur = 0; } int get(int key) { if( is_exist(key) ) { //get down the loc node ListNode *loc = mkv[key].p; loc->pre->next = loc->next; loc->next->pre = loc->pre; //insert into the front of the head loc->next = head->next; loc->pre = head; head->next = loc; loc->next->pre = loc; return mkv[key].val; } else { return -1; } } void set(int key , int value) { if( is_exist(key) ) { mkv[key].val = value; ListNode *q = mkv[key].p; q->value = value; return ; } ListNode *tmp = new ListNode(key,value); if(capacity_cur<capacity) { if(head->next==NULL) //the list is empty { head->next = tmp ; head->pre = tmp; tmp->next = head; tmp->pre = head; tValue tv(value,tmp); mkv[key] = tv; ++capacity_cur; } else //insert the tmp into the front of the list { tmp->next = head->next; tmp->pre = head; head->next->pre = tmp; head->next = tmp; tValue tv(value,tmp); mkv[key] = tv; ++capacity_cur; } } else { //get rid of the lru node ListNode *tail = head->pre; head->pre = tail->pre; tail->pre->next = head; mkv.erase(tail->key); delete tail; //insert into the new node tmp->next = head->next; tmp->pre = head; head->next->pre = tmp; head->next = tmp; tValue tv(value,tmp); mkv[key] = tv; } } bool is_exist(int key) { return ( mkv.find(key) != mkv.end() ); } void print() { ListNode *p = head->next; while(p!=head) { cout<<"key = "<<p->key<<" Value = "<<p->value<<endl; p = p->next; } cout<<endl; } };
#include<iostream> #include<vector> #include<map> using namespace std; class LRUCache { private: int capacity; int capacity_cur; typedef struct ListNode { int key; int value; struct ListNode* next; struct ListNode* pre; ListNode(int k , int v):key(k),value(v),next(NULL),pre(NULL) {} }ListNode; ListNode *head; typedef struct Value { int val; ListNode *p; Value(int _v,ListNode *pp):val(_v),p(pp){} Value() {} //if this constructor is not defined,there will be wrong }tValue; map< int,tValue > mkv; map< int,tValue > :: iterator it; public: LRUCache(int capacity) { this->capacity = capacity; head = new ListNode(0,0); capacity_cur = 0; } int get(int key) { if( is_exist(key) ) { //get down the loc node ListNode *loc = mkv[key].p; loc->pre->next = loc->next; loc->next->pre = loc->pre; //insert into the front of the head loc->next = head->next; loc->pre = head; head->next = loc; loc->next->pre = loc; return mkv[key].val; } else { return -1; } } void set(int key , int value) { if( is_exist(key) ) { //change the value in map and the list mkv[key].val = value; ListNode *q = mkv[key].p; q->value = value; //get the node and insert into the head of the list q->pre->next = q->next; q->next->pre = q->pre; q->next = head->next; q->pre = head; head->next->pre = q; head->next = q; return ; } ListNode *tmp = new ListNode(key,value); if(capacity_cur<capacity) { if(head->next==NULL) //the list is empty { head->next = tmp ; head->pre = tmp; tmp->next = head; tmp->pre = head; tValue tv(value,tmp); mkv[key] = tv; ++capacity_cur; } else //insert the tmp into the front of the list { tmp->next = head->next; tmp->pre = head; head->next->pre = tmp; head->next = tmp; tValue tv(value,tmp); mkv[key] = tv; ++capacity_cur; } } else { //get rid of the lru node ListNode *tail = head->pre; head->pre = tail->pre; tail->pre->next = head; mkv.erase(tail->key); delete tail; //insert into the new node tmp->next = head->next; tmp->pre = head; head->next->pre = tmp; head->next = tmp; tValue tv(value,tmp); mkv[key] = tv; } } bool is_exist(int key) { return ( mkv.find(key) != mkv.end() ); } void print() { ListNode *p = head->next; while(p!=head) { cout<<"key = "<<p->key<<" Value = "<<p->value<<endl; p = p->next; } cout<<endl; } }; int main() { /* LRUCache lru(3); lru.set(1,10); lru.print(); lru.set(2,20); lru.print(); lru.set(3,30); lru.print(); cout<<"get key = "<<1<<",Value = "<<lru.get(1)<<endl; lru.print(); lru.set(4,40); lru.print(); cout<<"get key = "<<3<<",Value = "<<lru.get(3)<<endl; lru.print(); lru.set(5,50); lru.print(); LRUCache lru1(2); lru1.set(2,1); lru1.print(); lru1.set(2,2); lru1.print(); cout<<"get key = "<<2<<",Value = "<<lru1.get(2)<<endl; lru1.set(1,1); lru1.print(); lru1.set(4,1); lru1.print(); cout<<"get key = "<<2<<",Value = "<<lru1.get(2)<<endl; */ LRUCache lru1(2); lru1.set(2,1); lru1.print(); lru1.set(1,1); lru1.print(); lru1.set(2,3); lru1.print(); lru1.set(4,1); lru1.print(); cout<<"get key = "<<1<<",Value = "<<lru1.get(1)<<endl; cout<<"get key = "<<2<<",Value = "<<lru1.get(2)<<endl; return 0; }
【leetcode】:LRU Cache_缓存淘汰算法LRU的设计与实现
原文地址:http://blog.csdn.net/lavorange/article/details/41852921