当前位置: 首页 > news >正文

146. LRU 缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

示例:

输入
[“LRUCache”, “put”, “put”, “get”, “put”, “get”, “put”, “get”, “get”, “get”]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4

提示:

1 <= capacity <= 3000
0 <= key <= 10000
0 <= value <= 105
最多调用 2 * 105 次 get 和 put

LRU缓存是经典的内存管理机制,实现方法是使用哈希表和双向链表为基础,通过互相映射,实现O(1)的平均算法时间

实现代码如下:

// 增加一个头节点和尾节点方便处理
// 使用哈希表和双向链表来完成
// 哈希表 通过key 指向双向链表的存储value的节点
// 双向链表 存储value值,同时双向链表头部节点表示最新使用的,尾部节点表示最长时间没有使用的,如果摘除的话从尾部节点摘除,从头部节点插入struct Node {int value;int key;struct Node *next;struct Node *prev;
};typedef struct {struct Node *Hash[10010];struct Node *ListHead;struct Node *ListTail;int ListCount;int ListMaxCount;
} LRUCache;LRUCache* lRUCacheCreate(int capacity) {LRUCache *obj = (LRUCache*)malloc(sizeof(LRUCache));if (obj == NULL) {return obj;}int i;for (i = 0; i < 10010; i++) {obj->Hash[i] = NULL;}obj->ListCount = 0;obj->ListMaxCount = capacity;obj->ListHead = (struct Node*)malloc(sizeof(struct Node));obj->ListTail = (struct Node*)malloc(sizeof(struct Node));obj->ListHead->next = obj->ListTail;obj->ListHead->prev = NULL;obj->ListTail->prev = obj->ListHead;obj->ListTail->next = NULL;return obj;
}int lRUCacheGet(LRUCache* obj, int key) {// 判断元素是否存在,不存在直接返回-1, 如果存在,返回value,同时将node节点放到head位置if (obj->Hash[key] == NULL) {return -1;}struct Node *tmpNode = obj->Hash[key];// 先将节点摘除下来tmpNode->next->prev = tmpNode->prev;tmpNode->prev->next = tmpNode->next;// 将节点放到头结点后面tmpNode->next = obj->ListHead->next;obj->ListHead->next->prev = tmpNode;tmpNode->prev = obj->ListHead;obj->ListHead->next = tmpNode;return obj->Hash[key]->value;
}void lRUCachePut(LRUCache* obj, int key, int value) {// 首先判断元素是否存在if (obj->Hash[key] != NULL) {obj->Hash[key]->value = value;struct Node *tmpNode = obj->Hash[key];// 先将节点摘除下来tmpNode->next->prev = tmpNode->prev;tmpNode->prev->next = tmpNode->next;// 将节点放到头结点后面tmpNode->next = obj->ListHead->next;obj->ListHead->next->prev = tmpNode;tmpNode->prev = obj->ListHead;obj->ListHead->next = tmpNode;return;}//如果不存在,插入节点,如果超过最大数量,将链表尾部节点抛弃// 插入新节点插入到节点头struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));newNode->value = value;newNode->key = key;obj->Hash[key] = newNode;// 将节点放到头结点后面newNode->next = obj->ListHead->next;obj->ListHead->next->prev = newNode;newNode->prev = obj->ListHead;obj->ListHead->next = newNode;(obj->ListCount)++;if (obj->ListCount > obj->ListMaxCount) { //超过最大数量,将链表尾部节点抛弃struct Node *tmpNode = obj->ListTail->prev;tmpNode->prev->next = obj->ListTail;obj->ListTail->prev = tmpNode->prev;obj->Hash[tmpNode->key] = NULL;free(tmpNode);(obj->ListCount)--;}
}void lRUCacheFree(LRUCache* obj) {struct Node *tmpNode = NULL;while(obj->ListHead != NULL) {tmpNode = obj->ListHead;obj->ListHead = obj->ListHead->next;free(tmpNode);}free(obj);
}/*** Your LRUCache struct will be instantiated and called as such:* LRUCache* obj = lRUCacheCreate(capacity);* int param_1 = lRUCacheGet(obj, key);* lRUCachePut(obj, key, value);* lRUCacheFree(obj);
*/

相关文章:

  • 蓝桥杯每日一题2023.11.16
  • 51.Sentinel微服务保护
  • 网络运维Day18
  • YOLOV5部署Android Studio安卓平台NCNN
  • 从零开始的C++(十七)
  • flask创建步骤
  • 利用 Pandoc + ChatGPT 优雅地润色论文,并保持 Word 公式格式:Pandoc将Word和LaTeX文件互相转化
  • 第八章 应用参数为约束建模 P1|系统建模语言SysML实用指南学习
  • 迭代新品 | 第四代可燃气体监测仪,守护燃气管网安全快人一步
  • qt-C++笔记之treeWidget初次使用
  • Sql Server 2017主从配置之:事务日志传送
  • P3879 [TJOI2010] 阅读理解- 字典树
  • Java方法中不使用的对象应该手动赋值为NULL吗?
  • JS 新操作符 —— “?.”、“??”、“??=”
  • Excel 文件比较工具 xlCompare 11.01 Crack
  • 【Leetcode】101. 对称二叉树
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【剑指offer】让抽象问题具体化
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • CEF与代理
  • Django 博客开发教程 16 - 统计文章阅读量
  • echarts花样作死的坑
  • es6(二):字符串的扩展
  • Fabric架构演变之路
  • flutter的key在widget list的作用以及必要性
  • Intervention/image 图片处理扩展包的安装和使用
  • java2019面试题北京
  • JavaScript新鲜事·第5期
  • Median of Two Sorted Arrays
  • opencv python Meanshift 和 Camshift
  • springboot_database项目介绍
  • webpack4 一点通
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 基于组件的设计工作流与界面抽象
  • 排序算法学习笔记
  • 排序算法之--选择排序
  • 深度学习在携程攻略社区的应用
  • 使用parted解决大于2T的磁盘分区
  • 突破自己的技术思维
  • 微信开源mars源码分析1—上层samples分析
  • 系统认识JavaScript正则表达式
  • 在weex里面使用chart图表
  • Linux权限管理(week1_day5)--技术流ken
  • 通过调用文摘列表API获取文摘
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • (安卓)跳转应用市场APP详情页的方式
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)基于IDEA的JAVA基础1
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)http-server应用
  • .axf 转化 .bin文件 的方法
  • .NET Core WebAPI中封装Swagger配置