zoukankan      html  css  js  c++  java
  • LeetCode146: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.

    解题思路:

    利用双向链表+hashtable实现

    Cache中的存储空间往往是有限的,当Cache中的存储块被用完,而需要把新的数据Load进Cache的时候,我们就需要设计一种良好的算法来完成数据块的替换。LRU的思想是基于“最近用到的数据被重用的概率比较早用到的大的多”这个设计规则来实现的。

    为了能够快速删除最久没有访问的数据项和插入最新的数据项,我们双向链表连接Cache中的数据项,并且保证链表维持数据项从最近访问到最旧访问的顺序。每次数据项被查询到时,都将此数据项移动到链表头部(O(1)的时间复杂度)。这样,在进行过多次查找操作后,最近被使用过的内容就向链表的头移动,而没有被使用的内容就向链表的后面移动。当需要替换时,链表最后的位置就是最近最少被使用的数据项,我们只需要将最新的数据项放在链表头部,当Cache满时,淘汰链表最后的位置就是了。
        查找一个链表中元素的时间复杂度是O(n),每次命中的时候,我们就需要花费O(n)的时间来进行查找,怎么样才能提高查找的效率呢?当然是hashtable了,因为它的查找时间复杂度是O(1)。

    实现代码:

    #include <iostream>
    #include <unordered_map>
    
    using namespace std;
    /*
    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.
    */
    
    //双向链表节点 
    struct LRUNode
    {
        int key;
        int val;
        LRUNode *pre;
        LRUNode *next;
        LRUNode(int k = 0, int v = 0):key(k), val(v),pre(NULL), next(NULL){
        } 
    };
    class LRUCache{
    public:
        LRUCache(int capacity):cap(capacity),size(0) {
            head = new LRUNode();
            tail = new LRUNode();
            head->next = tail;
            tail->pre = head;
                 
        }
        
        int get(int key) {
            LRUNode *t = hashtable[key];
            if(t)//key在hashtable存在,则调整该key在链表中对应节点的位置,将其插入到最前面 
            {
                //分离t节点 
                t->pre->next = t->next;
                t->next->pre = t->pre;
                //将t节点插入到头结点之后,即第一个数据节点 
                t->pre = head;
                t->next = head->next;
                head->next = t;
                t->next->pre = t;
                return t->val;
                
            }
            else
                return -1;
            
        }
        
        void set(int key, int value) {
            LRUNode *t = hashtable[key];
            if(t)//key在hashtable存在,则更新value及调整该key对应节点在链表中位置,将其插入到第一个节点 
            {
                t->val = value;
                //分离t节点 
                t->pre->next = t->next;
                t->next->pre = t->pre;
                //将t节点插入到头结点之后,即第一个数据节点
                t->pre = head;
                t->next = head->next;
                head->next = t;
                t->next->pre = t;
                return ;
                
            }
    
            if(size == cap)//如果双向链表容量已满即缓存容量已满,则将最近不使用的节点即链表最后一个数据节点删除 
            {
                LRUNode *tmp = tail->pre;
                tail->pre->pre->next = tail;           
                tail->pre = tmp->pre;
                hashtable.erase(tmp->key);
                delete tmp;
                size--;
            }
            
            //创建key对应的一个新节点,插入到最前面 
            LRUNode *node = new LRUNode(key, value);
            
            node->pre = head;
            node->next = head->next;
            head->next = node;
            node->next->pre = node;
            
            hashtable[key] = node;//在hashtable添加key对应的表项 
            
            size++;//链表节点数++ 
            
            
        }
    private:
        int cap;//链表容量即缓存容量 
        int size;//缓存当前使用量 
        LRUNode *head;//链表头结点,不存数据, 
        LRUNode *tail;//链表尾节点,不存数据 
        unordered_map<int,LRUNode*> hashtable;//hashtable,用作查找O(1)时间复杂度 
        
    };
    int main(void)
    {
        LRUCache lrucache(3);
        lrucache.set(1,8);
        lrucache.set(2,9);
        lrucache.set(3,10);
        lrucache.set(4,11);
        cout<<lrucache.get(1)<<endl;
        cout<<lrucache.get(2)<<endl;
        cout<<lrucache.get(4)<<endl;
    
        
        return 0;
    }
  • 相关阅读:
    Mac上反编译Android apk安装包
    静态链表
    x = x &(x-1)
    C语言itoa()函数和atoi()函数
    以文本方式和二进制方式操作文件
    自己实现memcpy,strcpy与strncpy
    实现中英文混合string的逆向输出
    实现纯英文string的逆序输出
    C语言实现字符串逆序输出
    ASCII码对照表
  • 原文地址:https://www.cnblogs.com/mickole/p/3670445.html
Copyright © 2011-2022 走看看