页面置换算法LRU实现--leetcode O(1)时间复杂度

转载
作者:鱼与海洋
出处:http://www.cnblogs.com/joannacode/p/5998949.html


leetcode题目地址

https://leetcode.com/problems/lru-cache/

题目描述

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

get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(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.

Follow up:
Could you do both operations in O(1) time complexity?

Example:

LRUCache cache = new LRUCache( 2 /* capacity */ );

cache.put(1, 1);
cache.put(2, 2);
cache.get(1);       // returns 1
cache.put(3, 3);    // evicts key 2
cache.get(2);       // returns -1 (not found)
cache.put(4, 4);    // evicts key 1
cache.get(1);       // returns -1 (not found)
cache.get(3);       // returns 3
cache.get(4);       // returns 4

Subscribe to see which companies asked this question.

ac代码

采用 双向链表 + map(效率还是不错的 map进一步可用成unordered_map)

  • 数据结构设计
    这里写图片描述

这里写图片描述

typedef struct node{
    int key;
    int val;
    struct node* pre;
    struct node* next;
    node(int _key = -1, int _val = -1)
    {
        key = _key;
        val = _val;
        pre = NULL;
        next = NULL;
    }
}DNode;

class LRUCache
{
public:

    LRUCache(int _capacity) {
        capacity = _capacity;
        size = 0;
        head = new DNode();
        tail = new DNode();
        head->next = tail;
        tail->pre = head;
        mp.clear();
    }

    int get(int key) {
        map<int,DNode*>::iterator it= mp.find(key);
        if(it == mp.end())  //如果在Cache中不存在该key, 则返回-1
        {
            return -1; 
        }
        else
        {
            DNode* t =  it->second;
            // 把 t分离出来,然后将t插入到头部位置

            t->pre->next = t->next;
            t->next->pre = t->pre;


            t->pre = head;
            t->next = head->next;
            head->next = t;
            t->next->pre = t;

            return t->val;
        }  
    }

    void put(int key, int value) {
        map<int,DNode*>::iterator it= mp.find(key);
        if(it == mp.end())  //如果在Cache中不存在该key, 则返回-1
        {

            if(size == capacity) //如果双向链表容量已满即缓存容量已满,则将最近不使用的节点即链表最后一个数据节点删除 
            {
                // 删除最后一个
                DNode *tmp = tail->pre;
                tail->pre->pre->next = tail;           
                tail->pre = tmp->pre;

                mp.erase(tmp->key);
                delete tmp;
                size--;
            }

            //把新节点插入到head的后面 更新map
            DNode *newNode = new DNode(key, value);

            newNode->pre = head;
            newNode->next = head->next;
            head->next = newNode;
            newNode->next->pre = newNode;

            mp[key] = newNode;//在hashtable添加key对应的表项 

            size++;//链表节点数++ 

        }else{ // 当前put的可以存在,需要更新value

            DNode* t =  it->second;
            // 把 t分离出来,然后将t插入到头部位置
            t->pre->next = t->next;
            t->next->pre = t->pre;

            t->val = value; //**

            t->pre = head;
            t->next = head->next;
            head->next = t;
            t->next->pre = t;

            return;
        }
    }

private:
    int capacity;
    int size;
    DNode* head; 
    DNode* tail;
    map<int,DNode*> mp;
};

ac2 (C++ list + map)

考虑到c++ list本身就是个 双向链表,可以直接采用list(效率会比较差,不过能ac)

这里写图片描述

class LRUCache
{
public:

    LRUCache(int _capacity) {
        capacity = _capacity;
        size = 0;
        cachelist.clear();
        mp.clear();
    }

    int get(int key) {
        map<int,pair<int,int>>::iterator it= mp.find(key);
        if(it == mp.end())  //如果在Cache中不存在该key, 则返回-1
        {
            return -1; 
        }
        else
        {
            pair<int,int> t = it->second;
            pair<int,int> newPair(t.first, t.second);

            cachelist.remove(t);
            cachelist.push_front(newPair);

            return newPair.second;
        }  
    }

    void put(int key, int value) {
        map<int,pair<int,int>>::iterator it= mp.find(key);
        if(it == mp.end())  //如果在Cache中不存在该key, 则返回-1
        {

            if(size == capacity) //如果双向链表容量已满即缓存容量已满,则将最近不使用的节点即链表最后一个数据节点删除 
            {

                pair<int,int> tmp = cachelist.back();
                cachelist.pop_back();

                mp.erase(tmp.first);
                size--;
            }

            pair<int,int> newPair(key,value);
            cachelist.push_front(newPair);
            mp[key] = newPair;
            size++;//链表节点数++ 

        }else{ // 当前put的可以存在,需要更新value

            pair<int,int> t = it->second;
            pair<int,int> newPair(key,value);

            cachelist.remove(t);
            cachelist.push_front(newPair);

            mp[t.first] = newPair;

            return;
        }
    }

private:
    int capacity;
    int size;
    list<pair<int,int>> cachelist;
    map<int, pair<int,int>> mp;
};

ac3

按照数据结构图的思想来写代码会容易很多

typedef struct node
{
    int key;
    int val;
    struct node* next;
    struct node* pre;
    node(int _key = -1, int _val = -1){
        key = _key;
        val = _val;
        next = NULL;
        pre = NULL;
    }
}Dnode;

class LRUCache {
public:

    int size;
    int cap;
    Dnode* head;
    Dnode* tail;
    map<int, Dnode*> mp;

    LRUCache(int capacity) {
        size = 0;
        cap =capacity;
        head = new Dnode;
        tail = new Dnode;

        head->next = tail;
        tail->pre = head;
    }

    int get(int key) {
        if(mp.count(key) == 0)
            return -1;

        Dnode*  oldPos = mp[key];
        int val = oldPos->val; //要返回的val

        Dnode* oldpre = oldPos->pre;
        oldPos->next->pre = oldpre;
        oldpre->next = oldPos->next;

        delete oldPos;
        mp.erase(key);

        Dnode* newPos = new Dnode(key,val);

        head->next->pre = newPos;
        newPos->next = head->next;
        newPos->pre = head;
        head->next = newPos;

        mp[key] = newPos;

        return val;
    }

    void put(int key, int value) {
        if(cap <= 0)
            return;

        int storeVal = get(key);
        if(storeVal != -1)
        {
            head->next->val = value;
            mp[key]->val = value;

            return;
        }

        if(size == cap)
        {
            Dnode* delNode = tail->pre;
            int delKey = delNode->key;
            Dnode* delpre = tail->pre->pre;

            delpre->next = tail;
            tail->pre= delpre;

            delete delNode;
            mp.erase(delKey);
            size --;
        }

        Dnode* newPos = new Dnode(key,value);

        head->next->pre = newPos;
        newPos->next = head->next;
        newPos->pre = head;
        head->next = newPos;

        mp[key] = newPos;
        size ++;
    }
};

上面的代码,改进一下get方法(可以优化一点运行时间)

int get(int key) {
    if(mp.count(key) == 0)
        return -1;

    Dnode*  oldPos = mp[key];
    int val = oldPos->val; //要返回的val

    Dnode* oldpre = oldPos->pre;
    oldPos->next->pre = oldpre;
    oldpre->next = oldPos->next;

    //delete oldPos;
    //mp.erase(key);

    //Dnode* newPos = new Dnode(key,val);
    Dnode* newPos = oldPos; //直接更新

    head->next->pre = newPos;
    newPos->next = head->next;
    newPos->pre = head;
    head->next = newPos;

    mp[key] = newPos;// 直接更新

    return val;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值