对于web开发而言,缓存必不可少,也是提升性能最经常使用的方式。不管是浏览器缓存(若是是chrome浏览器,能够经过chrome:://cache查看),仍是服务端的缓存(经过memcached或者redis等内存数据库)。缓存不只能够加速用户的访问,同时也能够下降服务器的负载和压力。那么,了解常见的缓存淘汰算法的策略和原理就显得特别重要。node
像浏览器的缓存策略、memcached的缓存策略都是使用LRU这个算法,LRU算法会将近期最不会访问的数据淘汰掉。LRU如此流行的缘由是实现比较简单,并且对于实际问题也很实用,良好的运行时性能,命中率较高。下面谈谈如何实现LRU缓存:c++
LRU Cache具有的操做:git
LRU实现采用双向链表 + Map 来进行实现。这里采用双向链表的缘由是:若是采用普通的单链表,则删除节点的时候须要从表头开始遍历查找,效率为O(n),采用双向链表能够直接改变节点的前驱的指针指向进行删除达到O(1)的效率。使用Map来保存节点的key、value值便于能在O(logN)的时间查找元素,对应get操做。github
双链表节点的定义:web
struct CacheNode { int key; // 键 int value; // 值 CacheNode *pre, *next; // 节点的前驱、后继指针 CacheNode(int k, int v) : key(k), value(v), pre(NULL), next(NULL) {} };
对于LRUCache这个类而言,构造函数须要指定容量大小redis
LRUCache(int capacity) { size = capacity; // 容量 head = NULL; // 链表头指针 tail = NULL; // 链表尾指针 }
双链表的节点删除操做:算法
void remove(CacheNode *node) { if (node -> pre != NULL) { node -> pre -> next = node -> next; } else { head = node -> next; } if (node -> next != NULL) { node -> next -> pre = node -> pre; } else { tail = node -> pre; } }
将节点插入到头部的操做:chrome
void setHead(CacheNode *node) { node -> next = head; node -> pre = NULL; if (head != NULL) { head -> pre = node; } head = node; if (tail == NULL) { tail = head; } }
get(key)操做的实现比较简单,直接经过判断Map是否含有key值便可,若是查找到key,则返回对应的value,不然返回-1;数据库
int get(int key) { map<int, CacheNode *>::iterator it = mp.find(key); if (it != mp.end()) { CacheNode *node = it -> second; remove(node); setHead(node); return node -> value; } else { return -1; } }
set(key, value)操做须要分状况判断。若是当前的key值对应的节点已经存在,则将这个节点取出来,而且删除节点所处的原有的位置,并在头部插入该节点;若是节点不存在节点中,这个时候须要在链表的头部插入新节点,插入新节点可能致使容量溢出,若是出现溢出的状况,则须要删除链表尾部的节点。浏览器
void set(int key, int value) { map<int, CacheNode *>::iterator it = mp.find(key); if (it != mp.end()) { CacheNode *node = it -> second; node -> value = value; remove(node); setHead(node); } else { CacheNode *newNode = new CacheNode(key, value); if (mp.size() >= size) { map<int, CacheNode *>::iterator iter = mp.find(tail -> key); remove(tail); mp.erase(iter); } setHead(newNode); mp[key] = newNode; } }
至此,LRU算法的实现操做就完成了,完整的源码参考:https://github.com/cpselvis/leetcode/blob/master/solution146.cpp