LRU的實現

來源1:http://blog.csdn.net/tinyway/article/details/24536327html

來源2:https://www.cnblogs.com/mushroom/p/4278275.html#o1node

來源3:雙向列表的插入順序: https://www.cnblogs.com/Renyi-Fan/p/7512789.html數組

 

 LRU便是:把最近最少訪問的數據給淘汰掉,常常被訪問到便是熱點數據。數據結構

關於LRU數據結構:由於key優先級提高和key淘汰,因此須要順序結構。函數

新數據插入到鏈表頭部、被命中時的數據移動到頭部,添加複雜度O(1),移動和獲取複雜度O(N)。spa

 

LRU的實現有這樣幾種思路:.net

一、利用數組保存節點信息,另外節點信息除了內容還須要保存最近使用狀況。code

缺點:每次都須要遍從來找信息,同時也要遍從來刪除(指LRU cache滿了的狀況)htm

二、鏈表來保存節點,雙向鏈表,最末端爲最新使用的,這樣能減小刪除時候的時間效率。blog

三、還能夠用一個哈希表來儲存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的待完成。

相關文章
相關標籤/搜索