C++11模拟实现虚拟内存管理LRU算法

之前在学习操作系统内存管理的时候接触过LRU,但是也没想过用C++来模拟LRU缓存机制,可是在刷题的时候,碰到了这一题(leetcode第146题:
链接: https://leetcode-cn.com/problems/lru-cache/,觉得很有意思,而且用C++11模拟实现的代码可以说很优雅,所以写篇博文,纪念一下!

LRU算法的理念

LRU即Least Recently Used的缩写,最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。
大致理念就是:
如果某数据项被访问,则推断该数据项再次被访问的几率很大,于是把数据项移动到最容易访问到的位置,如链表头;
如果需要插入某数据项,先检查设定的内存有没有满,满了就删除链表尾部的数据项(也就是很久都没有被访问的数据项),再在链表头部插入该数据项,如果内存没满,就直接在链表头插入数据项。

分析C++11模拟实现虚拟内存管理LRU算法_第1张图片

选择std::list和std::unordered_map作为基础的数据结构,哈希表能保证O(1)的时间内查找节点,而双链表的插入、删除效率高,保证了LRU的查找、插入、删除操作都有较高的性能。

具体细节

1 越靠近链表头,说明该数据项越近被访问,越靠近链表尾,该数据项离上次访问时间越久;
2 访问数据项时,如果数据项存在,则把该数据项移动到链表头,同时更新哈希表中的该数据项的地址;
3 插入数据项时,如果设定的内存值已经满了,则把链表尾,及离上次访问最久的数据项删除,同时在哈希表中删除这一项,数据项插入链表头。

接下来是把上面思路翻译成代码:

class LRUCache {
private:
    struct cachenode{    
        int key;    
        int value;    
        cachenode(int k,int v):key(k),value(v){}
        };//一个数据项,根据key,得到相应的value

public:    
    LRUCache(int capacity) {        
        this->capacity=capacity;   
     }//构造函数,传入设定的大小        

    int get(int key) {        
        if(cacheMap.find(key)==cacheMap.end())          
            return -1;//没有该数据项,直接返回-1

    cacheList.splice(cacheList.begin(),cacheList,cacheMap[key]);            
    cacheMap[key]=cacheList.begin();
    //把访问的数据项移动到链表头,并更新哈希表中相应的值
     return cacheList.begin()->value;    
    }        


    void put(int key, int value) {            
        if(cacheMap.find(key)==cacheMap.end()){                 
            if(cacheMap.size()==capacity){//已经满了,直接删除链表尾部数据项                
                cacheMap.erase(cacheList.back().key);                 
                cacheList.pop_back();             
                }             
            cacheList.push_front(cachenode(key,value));             
            cacheMap[key]=cacheList.begin();         
            }else{             
                cacheMap[key]->value=value;
                cacheList.splice(cacheList.begin(),cacheList,cacheMap[key]);         }
    
    }
private:
    std::list<cachenode> cacheList;
    std::unordered_map<int,std::list<cachenode>::iterator>   cacheMap;
    int capacity;
};

关于std::splice()函数注释:
splice()函数很有用,std::list中有三个重载成员函数:
1、 list1.splice(iterator1,list2)
直接把list2剪切到list1的位置iterator1前面;
2、 list1.splice(iterator1,list2,iterator2)
把链表list2的位置iterator2的值剪切到list1的位置iterator1前面;
3、 list1.splice(iterator1,list2,iterator2,iterator3)
把链表list2的位置iterator2到位置iterator3的部分剪切到list1的位置iterator1前面;

你可能感兴趣的:(数据结构)