C++自己实现LRU

本文详细介绍了LRU(LeastRecentlyUsed,最近最少使用)数据结构的C++实现,包括如何在O(1)时间复杂度下进行get和set操作,以及如何维护最多K个元素的限制。通过使用map和list的数据结构配合,展示了LRU的具体实现过程。
摘要由CSDN通过智能技术生成

说明

笔试和面试的时候,经常需要手写LRU,这是一个非常好的数据结构,可以O(1)获取数据,而且还可以自动删除最久未使用的元素。

需求,LRU最多可以存储K个元素,有两个操作get和set:

get存在返回结果,并且更新到最新。

set不存在插入,存在修改值并且更新到最新。

测试数据:

第一行N,K,分别表示接下来多少行,以及LRU最大节点数量。

接下来每一行

1表示set,2表示get

7 2
1 1 1
1 2 2
1 3 3
2 1
2 2
1 4 4
2 3 

应该输出 -1 2 -1

新版(用官方的list作为双lian表,易懂)

注意了,list<Node*>::iterator 相当于指向list元素的指针,*it解引用就是一个Node*

struct Node{
    int k, v;
};

struct LRU{
    map<int, list<Node*>::iterator> mp;
    list<Node*> li;
    int K;
    LRU(int k): K(k){}

    void set(int k, int v){
        // 如果不存在 插入 并且 判断是否删除最后
        if(mp.count(k)==0){
            Node* cur = new Node{k, v};
            li.push_front(cur);
            mp.insert({k, li.begin()});

            if(mp.size()>K){
                // delete mp
                auto del = li.back();
                auto it = mp[del->k];
                mp.erase(del->k);
                // del list
                li.pop_back();
            }

        }
        //否则更新
        else{
            list<Node*>::iterator it = mp[k];
            (*it) -> v = v;
            get(k);
        }
    }

    int get(int k){
        // 如果存在 更新
        if(mp.count(k)){
            list<Node*>::iterator it = mp[k];
            // 摘除
            Node* cur = *it;
            li.erase(it);
            // 插入front
            li.push_front(cur);
            mp[k] = li.begin(); // mp也要更新
            return cur->v;
        }
        // 否则
        return -1;
    } 
};
int main(int argc, char *argv[])
{
    //将标准输入流重定向到 in.txt 文件
    // freopen("input.txt", "r", stdin);
    int N, K;
    cout << "N, K=";
    cin >> N >> K;
    LRU lru(K);
    while(N--){
        int op, k, v;
        cin >> op;
        if(op == 1){
            cin >> k >> v;
            lru.set(k,v);
        }else{
            cin >> k;
            int ret=lru.get(k);
            cout << ret << endl;
        }
    }
    return 0;
}
/// 
// g++ main.cpp -std=c++14 && ./a.out

代码 (旧版 原始 难懂)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>

using namespace std;
// 节点类型
struct Node
{
    int k, v;
    struct Node *pre, *nxt;
    Node(int i, int j): k(i), v(j)
    {
        pre = nullptr;
        nxt = nullptr;
    }
};
// 别名
using MAP=map<int, Node*>;
// 真正的LRU
class LRU
{
    int K_;  // 最大节点数量
    MAP M_;  // map
    Node* h_, *t_;  // 指向头尾的额外节点
public:
    LRU(int k){
        K_ = k;
        h_ = new Node(0,0);
        t_ = new Node(0,0);
        h_->nxt = t_; // 头尾节点需要互相连起来
        t_->pre = h_;
    }   
    void set(int k, int v){
        auto it = M_.find(k);
        if(it!=M_.end()){ // 如果存在
            Node* cur=it->second;
            cur->v = v; // update
            get(k); //更新即可
            return;
        }else{ //否则
            // new 创建
            Node* cur=new Node(k,v);
            Node* n = h_->nxt;
            // insert 
            cur->nxt = n;
            n->pre = cur;
            h_->nxt = cur;
            cur->pre = h_;
            M_.insert({k, cur});
            //need del ? 
            if (M_.size() > K_){
                Node* del=t_->pre;
                Node* p = del->pre;
                p->nxt = t_;
                t_->pre = p;
                M_.erase(del->k); // 别忘了这个
                delete del;
            }
        }
    }
    int get(int k){
        auto it = M_.find(k);
        if(it!=M_.end()){
            // del  别忘了先移除
            auto cur = it->second;
            auto p = cur->pre;
            auto n = cur->nxt;
            p->nxt = n;
            n->pre = p;
            // re insert 再插入
            n = h_->nxt;
            cur->nxt=n;
            n->pre  =cur;
            h_->nxt = cur;
            cur->pre = h_;
            return cur->v;
        }
        return -1;
    }
};

int main(int argc, char *argv[])
{
    //将标准输入流重定向到 in.txt 文件
    // freopen("input.txt", "r", stdin);
    int N, K;
    cout << "N, K=";
    cin >> N >> K;
    LRU lru(K);
    while(N--){
        int op, k, v;
        cin >> op;
        if(op == 1){
            cin >> k >> v;
            lru.set(k,v);
        }else{
            cin >> k;
            int ret=lru.get(k);
            cout << ret << endl;
        }
    }
    return 0;
}
/// 
// g++ main.cpp -std=c++14 && ./a.out
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值