LRU Cache 题解

题意

Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.

这道题的题意就是说,使用LRU Cache,就是将最新使用的放置在前面,以便下次取的时候方便,其余则依次往下移动;

思路

其实我也是根据别人的想法做的,用链表加入值,因为链表对于往前往后添加或者删除都非常方便,但是有个麻烦的地方在于,我并不知知道他的位置在哪里,只能循环去找,因此我使用了一个哈希数组进行存储她的key和下标;

实现

我的实现(比较白痴)

struct Node {
    int key;
    int value;
    Node(int _k, int _v) {key = _k; value = _v;}
};

class LRUCache{
public:
    unordered_map<int, int> maps;
    list<Node> lists;
    int size;
    LRUCache(int capacity) {
        size = capacity;
    }
    
    /**
     *  获取值,同时获取也算是一种访问
     *
     *  @param key <#key description#>
     *
     *  @return <#return value description#>
     */
    int get(int key) {
        if (maps.size() == 0) {
            return -1;
        }
        if (maps.find(key) != maps.end()) {
            auto key_value = maps.find(key);
            int j = 0;
            for (auto itr = lists.begin(); itr != lists.end() && j < lists.size(); itr++, j++) {
                if (j == key_value->second) {
                    int value = (*itr).value;
                    lists.push_front(Node((*itr).key, (*itr).value));
                    // 更新lists和maps
                    lists.erase(itr);
                    
                    // 将要更新的迭代器之前的下标都要加上1,其余的位置不需要改变
                    for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                        if (mitr->second < key_value->second){
                            mitr->second++;
                        }
                    }
                    
                    // 更新全部位置
                    key_value->second = 0;
                    
                    return value;
                }
            }
        }
        return -1;
    }
    
    /**
     *  添加新值,不过需要注意的是当内存不够的情况下,需要删除掉最不经常使用的
     *
     *  @param key   <#key description#>
     *  @param value <#value description#>
     */
    void set(int key, int value) {
        if (lists.size() == size) {
            // 满了先进行删除
            list<Node>::iterator lend = --lists.end();
            lists.pop_back();
            
            int lkey = lend->key;
            maps.erase(maps.find(lkey));
            
            lists.push_front(Node(key, value));
            
            for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                mitr->second++;
            }
            
            maps.insert(make_pair(key, 0));
        }
        else {
            // 存在的话
            if (maps.find(key) != maps.end()) {
                auto key_value = maps.find(key);
                maps[key] = 0;
                for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                    if (mitr->second < key_value->second){
                        mitr->second++;
                    }
                }
                // 更新全部位置
                key_value->second = 0;
            }
            else {
                lists.push_front(Node(key, value));
                for (auto mitr = maps.begin(); mitr != maps.end(); mitr++) {
                    mitr->second++;
                }
                maps.insert(make_pair(key, 0));
            }
        }
    }
};


int main(int argc, const char * argv[]) {
    // insert code here...
    LRUCache cache(5);
    cache.set(1, 10);
    cache.set(2, 20);
    cache.set(3, 30);
    
    //cout << "cache..." << cache.get(2) << endl;
    
    cache.set(4, 40);
    cache.set(5, 50);
    
    cache.set(8, 80);
    
    //cout << "cache..." << cache.get(1) << endl;
    cout << "cache..." << cache.get(5) << endl;
    
    return 0;
}

如上面所说,我需要不停的去更新其的位置,这样才能根据正确的位置去获取到具体的结点信息;根据题目的要求,需要控制时间复杂度在1,所以需要需要一个哈希数组去记录其位置;但是我好像并没有做到,依旧使用了一个循环。。。

我的基础上优化

struct node{
    int key;
    int value;
    node(int k, int v):key(k), value(v){}
};

/*
 * 注意整体思路是,使用双向list每次set或get一个元素时都把这个元素放到list的头部,无需统计每个元素的操作次数,实际上LRU的意思
 * 就是根据元素最后被访问的时间来决定替换哪个,故list中尾部元素即被替换.
 * STL技巧:1、使用map的find方法来判断key是否已经存在,返回值和map的end迭代器比较;
            2、使用unordered_map,它是hash_map,存取时间都是O(1),用它存储元素的position迭代器,是为了方便splice函数调用
 *          list.splice(position, list, element_pos)函数作用是把list的element_pos处的元素插入到position位置,本题中
            为了移动元素到list头部
 */
class LRUCache{
    int size;
    list<node> values;
    unordered_map<int, list<node>::iterator> positions;
public:
    LRUCache(int capacity) {
        size = capacity;
    }
    
    int get(int key) {
        if(positions.find(key) != positions.end()){
            values.splice(values.begin(), values, positions[key]);
            positions[key] = values.begin();
            
            return values.begin()->value;
        }
        return -1;
    }
    
    void set(int key, int value) {
        if(positions.find(key) != positions.end()){
            values.splice(values.begin(), values, positions[key]);  //移动被访问元素到头部
            values.begin()->value = value;
            positions[key] = values.begin();  //更新其位置,注意此处的position只是一个指针,当此key在list中被挤到其他位置后,positions里保存的位置也会跟着变化,因为它仅仅是一个指向该结点的指针       
        }
        else if(values.size()<size){
            values.push_front(node(key, value));
            positions[key] = values.begin();
        }
        else{
            node last = values.back();
            values.pop_back();
            positions.erase(last.key);
            
            values.push_front(node(key, value));
            positions[key] = values.begin();
        }
    }
    
};

将我的int下标,改成了纪录链表的迭代器,这下使用了splice会很方便,同时控制了时间复杂度。

总结

并没有。

转载于:https://www.cnblogs.com/George1994/p/6287549.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU Cache是一种常见的缓存淘汰策略,LRU代表最近最少使用。在Java中,可以使用不同的方式来实现LRU Cache。 引用\[1\]中的代码展示了一种自定义的LRU Cache实现,使用了一个自定义的LRUCache类,并在main方法中进行了测试。在这个实现中,LRUCache类继承了LinkedHashMap,并重写了removeEldestEntry方法来实现缓存的淘汰策略。 引用\[2\]中的代码展示了另一种自定义的LRU Cache实现,同样使用了一个自定义的LRUCache类,并在main方法中进行了测试。这个实现中,LRUCache类同样继承了LinkedHashMap,并重写了removeEldestEntry方法来实现缓存的淘汰策略。 引用\[3\]中的代码展示了使用ArrayList实现LRU Cache的方式。在这个实现中,LRUCache类使用了一个ArrayList来存储缓存数据,并通过get和put方法来操作缓存。 总结来说,LRU Cache的Java实现可以使用自定义的类继承LinkedHashMap并重写removeEldestEntry方法,或者使用ArrayList来存储缓存数据。具体的实现方式可以根据需求和偏好选择。 #### 引用[.reference_title] - *1* *2* [Java——LRUCache](https://blog.csdn.net/m0_60867520/article/details/128361042)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [LRUCache的Java实现](https://blog.csdn.net/qq_39383118/article/details/103535985)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值