LRU缓存算法设计——哈希双端链表
原题在这里:
题意:实现满足O(1)时间复杂度的get和put操作的LRU算法。
analyse:
1.第一次做的时候,选用了图论中链式前向星+set哈希处理的解法
思路:翻译为图,也就是找num时间戳在capacity范围内的边
对于每一个key,就当作一个节点,每指向一个value就是一条边
get操作:
head[key]==0:
return -1
head[key]!=0:
找到对应的num时间戳,哈希set删除,并新建该边。
put操作:
如果哈希set中存在时间戳,那么删除
直接新建边
建边处理:
定义数组head,id,mp分别表示key指向num时间戳,num时间戳指向key,num时间戳指向value
哈希set,表示当前LRU存在的时间戳列表。
添加head、id、mp数组元素和set当前时间戳
如果set列表数量大于capacity,则情况set列表头时间戳对应的head对应的key值所指向的时间戳
code:

class LRUCache { //翻译在链式前向星图中就是,在num时间戳为固定范围内的边 vector<int> head, id, mp; // key指向num时间戳,num时间戳指向key,num时间戳指向value set<int> st; //存在的num时间戳表 int num, m; void add(int x, int y) { //如果有,固定删除head[x]所对应的边,但是不需要实际操作 mp.emplace_back(y); head[x] = ++num; id.emplace_back(x); st.insert(num); while (st.size() > m) { head[id[*st.begin()]] = 0; st.erase(st.begin()); } } public: LRUCache(int capacity) { num = 0, m = capacity; head = vector<int>(1e4 + 9); mp.clear(), id.clear(); id.emplace_back(0); mp.emplace_back(0); st.clear(); } int get(int key) { if (head[key] != 0) { int x = head[key], y = mp[x]; st.erase(x); add(key, mp[x]); return y; } return -1; } void put(int key, int value) { int x = head[key]; if (x) st.erase(x); //如果有,直接删除后添加 add(key, value); } };
2.标准解法,map哈希+双端链表
思路:map存key对应node节点,另外定义整数类型size表示链表节点数量。
get:
如果没有则-1,有则直接mp[key]->val,并且将该节点置于链表头。
put:
如果没有则新建,否则返回val并且置于表头。
如果数量大于capacity,那么将链表末尾节点删除。
code:

class LRUCache { struct Node { int key, val; Node *next, *prev; Node() : key(0), val(0), next(nullptr), prev(nullptr){}; Node(int x, int y) : key(x), val(y), next(nullptr), prev(nullptr){}; }; map<int, Node *> mp; Node *head, *tail; int size, mx; public: LRUCache(int capacity) { head = new Node(); tail = new Node(); head->next = tail; tail->prev = head; size = 0, mx = capacity; } void add(Node *node) { node->prev = head; node->next = head->next; head->next->prev = node; head->next = node; } void remove(Node *node) { node->prev->next = node->next; node->next->prev = node->prev; } void move(Node *node) { remove(node); add(node); } Node *Remove() { Node *node = tail->prev; remove(node); return node; } int get(int key) { if (mp.count(key) == 0) return -1; Node *node = mp[key]; move(node); return node->val; } void put(int key, int value) { if (mp.count(key) == 0) { Node *node = new Node(key, value); mp[key] = node; add(node); ++size; if (size > mx) { Node *removed = Remove(); mp.erase(removed->key); delete removed; --size; } } else { Node *node = mp[key]; node->val = value; move(node); } } };
3.优化解,时间戳哈希+双端链表
思路:引入一个vector和一个整型变量num时间戳,记录key对应的num时间戳。
限制于本题key数据范围为[0,1e4]。
code:

class LRUCache { struct Node { int key, val; Node *next, *prev; Node() : key(0), val(0), next(nullptr), prev(nullptr){}; Node(int x, int y) : key(x), val(y), next(nullptr), prev(nullptr){}; }; Node *head, *tail; int size, mx; vector<Node *> nums; vector<int> start; //存入每一个key对应的num int num; public: LRUCache(int capacity) { head = new Node(); tail = new Node(); head->next = tail; tail->prev = head; size = 0, mx = capacity; start = vector<int>(1e4 + 9, -1); num = 0; } void add(Node *node) { node->prev = head; node->next = head->next; head->next->prev = node; head->next = node; } void remove(Node *node) { node->prev->next = node->next; node->next->prev = node->prev; } void move(Node *node) { remove(node); add(node); } Node *Remove() { Node *node = tail->prev; remove(node); return node; } int get(int key) { if (start[key] == -1) return -1; Node *node = nums[start[key]]; move(node); return node->val; } void put(int key, int value) { if (start[key] == -1) { Node *node = new Node(key, value); start[key] = num++; nums.emplace_back(node); add(node); ++size; if (size > mx) { Node *removed = Remove(); start[removed->key] = -1; //不用真删除nums内节点 delete removed; --size; } } else { Node *node = nums[start[key]]; node->val = value; move(node); } } };
【Over】
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!