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的待完成。

posted @ 2018-02-09 00:23  Poison%  阅读(246)  评论(0编辑  收藏  举报