LRU的实现
来源1:http://blog.csdn.net/tinyway/article/details/24536327
来源2:https://www.cnblogs.com/mushroom/p/4278275.html#o1
来源3:双向列表的插入顺序: https://www.cnblogs.com/Renyi-Fan/p/7512789.html
LRU即是:把最近最少访问的数据给淘汰掉,经常被访问到即是热点数据。
关于LRU数据结构:因为key优先级提升和key淘汰,所以需要顺序结构。
新数据插入到链表头部、被命中时的数据移动到头部,添加复杂度O(1),移动和获取复杂度O(N)。
LRU的实现有这样几种思路:
1、利用数组保存节点信息,另外节点信息除了内容还需要保存最近使用情况。
缺点:每次都需要遍历来找信息,同时也要遍历来删除(指LRU cache满了的情况)
2、链表来保存节点,双向链表,最末端为最新使用的,这样能减少删除时候的时间效率。
3、还可以用一个哈希表来储存key值对应的节点的地址,这样就可以实现查找O(1),删除添加O(1)了
//用双向链表来作为LRU的结构 //其中表头表示早入表的节点,表尾表示最新的节点 struct ListNode{ string key; string value; ListNode* next; ListNode* pre; //struct的构造函数 ListNode(string k,string v):key(k),value(v),next(NULL),pre(NULL){} }; class LRUCache{ private: int cap; int nodeNum; ListNode pHead; ListNode PTail; public: LRUCache(int capacity):cap(capacity),nodeNum(0),pHead(NULL),pTail(NULL){} string get(string key){ if(pHead==NULL) return ''; ListNode *pNode = pHead; while(pNode != NULL){ if(pNode->key == key){ string val = pNode->value; DeleteFromList(pNode); AddToList(pNode); return val } pNode = pNode->next; } //key is not found return '' } void set(string key, string val){ ListNode pNode = pHead; //要考虑为已有的key重新赋值 while(pNode!=NULL){ if(pNode->key==key){ pNode->value = val; DeleteFromList(pNode); AddToList(pNode); return; } pNode = pNode->next; } //为一个新的key存值 pNode = new ListNode(key,val); AddToList(pNode); } //删除pNode void DeleteFromList(ListNode* pNode){ ListNode* pPre = pNode->pre; ListNode* pNext = pNode->next; nodeNum--; //将pPre的next指向pNext即删除,但要考虑pNode是链表头的情况 if(pPre==NULL) pHead=pNext; else pPre->next = pNext; //将pNext的pre指向pPre即删除,但要考虑pNode是链表尾的情况 if(pNext==NULL) pTail = pPre; else pNext->pre = pPre; } //将pNode添加到链表 void AddToList(ListNode* pNode){ if(nodeNum == cap){ ListNode* pTmp = pHead; pHead = pHead->next; DeleteFromList(pTmp); delete pTmp; AddToList(pNode); } else{ ++nodeNum; if(nodeNum == 1){ pHead = pNode; pTail = PNode; } else{ //对于尾端加链表,不仅仅是链表插入顺序,还要更新pTail pNode->pre = pTail; pNode->next = pTail->next; pTail->next = pNode; pTail = pNode; } } } } //双向链表维护:pHead,pTail,numNode这三个成员,平时的操作要注意numNode //边界情况一定要注意维护pHead和pTail。
基于map或是dict的待完成。