146. LRU缓存机制(C++)---设计类题目(使用 双向链表、pair类、哈希表)

题目详情

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。

获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥已经存在,则变更其数据值;如果密钥不存在,则插入该组「密钥/数据值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

 

进阶:
你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // 返回  1
cache.put(3, 3);    // 该操作会使得密钥 2 作废
cache.get(2);       // 返回 -1 (未找到)
cache.put(4, 4);    // 该操作会使得密钥 1 作废
cache.get(1);       // 返回 -1 (未找到)
cache.get(3);       // 返回  3
cache.get(4);       // 返回  4

 


 

前言

LRU
LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

扩展:
LFU
LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。

总的来说LFU策略就是依据访问频率来决定淘汰的。

使用容器 或 类型

1.序列容器中的list(双向链表)
①使用时包含头文件<list>
②任意位置插入和删除元素效率都很高
③不支持随机存取
④每个元素还有占用额外空间的指针


2.pair类
①使用时包含头文件<utility>
②pair类是一个类模板,它可以把两个不同类型的值组织在一起,然后可以通过first和second公共数据成员来访问这两个值
③pair对象常常作为元素被添加到map中

-使用方法
①pair对象的定义: 

pair<int, string> mapair(5, "Jack"); //调用构造函数pair
pair<int, string> otherPair; //直接赋值
otherPair.first = 6; //直接对数据成员赋值
otherPair.second = "Mike"; //直接对数据成员赋值

②函数模板make_pair()的配合使用,make_pair()能将两个变量构造成一个pair

pair<int, int> aPair = make_pair(5, 10);

3.无序关联容器里的unordered_map
因为内部实现了哈希表,因此其查找速度会非常快

 

-下面代码

class LRUCache {
public:
    int Cap;
    list<pair<int, int>> cache; //双向链表-装的是(key,value)元组
    unordered_map<int, list<pair<int, int>>::iterator> map; //哈希表-key映射到cache中(key,value)在cache的位置

    LRUCache(int capacity) {
        Cap = capacity;
    }
    
    int get(int key) {
        auto it = map.find(key);
        //密钥 (key) 不存在
        if(it == map.end()) return -1;

        //密钥 (key)存在,且需要把(key,value)放到cache的最前面去
        auto tmp = *map[key]; //tmp暂存(key,value)
        cache.erase(map[key]);
        cache.push_front(tmp);
        map[key] = cache.begin(); //更新map中关键字为key的元素 
        return tmp.second;
    }
    
    void put(int key, int value) {
        auto it = map.find(key);
        //密钥 (key) 不存在
        if(it == map.end()) {
            //缓存容量达到上限
            if(map.size() == Cap) {
                //删除map中关键字为 cache最后一个元素的key 的元素
                auto lastPair = cache.back();
                map.erase(lastPair.first);
                ////删除cache中最后一个元素
                cache.pop_back();
            }
            //容量没达到上限
            cache.push_front(make_pair(key, value));
            map[key]=cache.begin();
        } 
        //密钥 (key) 已存在
        else {
            //先删掉cache中原来的(key,old_value),再把新的(key,value)放到cache的最前面
            auto it = map[key];
            cache.erase(it);
            cache.push_front(make_pair(key, value));
            //再更新map中关键字为key的元素
            map[key] = cache.begin();
        }
    }
};


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章