【数据结构】LRU缓存

LRU缓存

LRU(Least Recently Used,最近最少使用)缓存是一种缓存淘汰策略,用于管理缓存中数据的存储和淘汰。LRU缓存会优先淘汰最近最少使用的数据,以便为新数据腾出空间。它通常用于提高应用程序的性能,通过缓存常用的数据来减少对磁盘或数据库的访问次数。

LRU缓存的基本原理

  • 缓存:LRU缓存通过一个数据结构(通常是字典或散列表)来存储缓存中的数据。数据可以通过键值对的形式存储和访问。
  • 淘汰策略:LRU缓存使用一个有序的数据结构(通常是双向链表)来跟踪数据的使用顺序。数据的插入、访问和删除操作都会更新链表中的数据顺序,以便保持最近最少使用的数据在链表的尾部。
  • 插入操作:当向缓存中插入新数据时,如果缓存已满,则会根据LRU策略删除最近最少使用的数据,然后插入新数据。
  • 访问操作:当访问缓存中的数据时,该数据会被移动到链表的头部,以表示它是最近被使用的数据。
  • 删除操作:当缓存已满且需要插入新数据时,会删除链表尾部的最近最少使用的数据。

LRU缓存的优点

  • 提高性能:LRU缓存通过缓存常用的数据,减少了对慢速存储设备(如磁盘或数据库)的访问次数,从而提高了应用程序的性能。
  • 自适应淘汰:LRU策略根据数据的访问频率和顺序自动调整缓存中的数据,从而保持缓存中的数据始终是最近最常用的数据。

LRU缓存的缺点

  • 内存开销:LRU缓存需要额外的内存来维护数据的有序链表。
  • 复杂性:实现LRU缓存需要维护数据的顺序,并处理数据的插入、访问和删除操作。

C语言中的LRU缓存示例

下面是一个使用C语言实现的LRU缓存示例,展示了基本的插入、访问和删除操作。

首先,定义LRU缓存的数据结构和相关操作:

#include <stdio.h>
#include <stdlib.h>// 定义缓存的最大大小
#define MAX_SIZE 3// 双向链表节点
typedef struct Node {int key;int value;struct Node *prev;struct Node *next;
} Node;// LRU缓存结构
typedef struct {Node *head;Node *tail;int size;Node *hashTable[MAX_SIZE];  // 哈希表,用于快速查找节点
} LRUCache;// 初始化LRU缓存
LRUCache *initLRUCache() {LRUCache *cache = (LRUCache *)malloc(sizeof(LRUCache));cache->head = NULL;cache->tail = NULL;cache->size = 0;for (int i = 0; i < MAX_SIZE; i++) {cache->hashTable[i] = NULL;}return cache;
}// 释放LRU缓存
void freeLRUCache(LRUCache *cache) {Node *current = cache->head;while (current != NULL) {Node *next = current->next;free(current);current = next;}free(cache);
}// 将节点移动到链表的头部
void moveToHead(LRUCache *cache, Node *node) {if (cache->head == node) {// 节点已经在头部return;}// 将节点从当前位置移除if (node->prev != NULL) {node->prev->next = node->next;} else {cache->head = node->next;}if (node->next != NULL) {node->next->prev = node->prev;} else {cache->tail = node->prev;}// 将节点插入到头部node->prev = NULL;node->next = cache->head;if (cache->head != NULL) {cache->head->prev = node;}cache->head = node;if (cache->tail == NULL) {cache->tail = node;}
}// 插入键值对到缓存中
void put(LRUCache *cache, int key, int value) {int hashIndex = key % MAX_SIZE;Node *node = cache->hashTable[hashIndex];while (node != NULL) {if (node->key == key) {// 键已存在,更新值并移动到头部node->value = value;moveToHead(cache, node);return;}node = node->next;}// 键不存在,创建新节点node = (Node *)malloc(sizeof(Node));node->key = key;node->value = value;node->prev = NULL;node->next = NULL;// 将新节点插入到头部moveToHead(cache, node);cache->hashTable[hashIndex] = node;cache->size++;// 如果缓存已满,删除最近最少使用的节点if (cache->size > MAX_SIZE) {Node *tailNode = cache->tail;// 从哈希表中移除int tailHashIndex = tailNode->key % MAX_SIZE;cache->hashTable[tailHashIndex] = NULL;// 从链表中移除cache->tail = tailNode->prev;if (cache->tail != NULL) {cache->tail->next = NULL;} else {cache->head = NULL;}free(tailNode);cache->size--;}
}// 从缓存中获取值
int get(LRUCache *cache, int key) {int hashIndex = key % MAX_SIZE;Node *node = cache->hashTable[hashIndex];while (node != NULL) {if (node->key == key) {// 键存在,移动到头部并返回值moveToHead(cache, node);return node->value;}node = node->next;}// 键不存在return -1;
}

在上面的代码中,定义了LRU缓存的数据结构 LRUCache,包含一个双向链表(用于跟踪数据的使用顺序)和哈希表(用于快速查找节点)。同时,定义了插入和访问操作。

  • 插入操作:当插入新键值对时,如果键已经存在,则更新值并将节点移动到链表的头部。如果键不存在,则创建新节点并插入到头部。如果缓存已满,则删除链表尾部的节点。
  • 访问操作:当访问缓存中的键时,如果键存在,则将节点移动到链表的头部并返回值;否则返回 -1。

接下来,示例代码展示了如何使用LRU缓存:

int main() {// 初始化LRU缓存LRUCache *cache = initLRUCache();// 插入键值对put(cache, 1, 100);put(cache, 2, 200);put(cache, 3, 300);// 获取值printf("获取键1的值:%d\n", get(cache, 1));  // 输出100printf("获取键2的值:%d\n", get(cache, 2));  // 输出200printf("获取键3的值:%d\n", get(cache, 3));  // 输出300// 插入新键值对,会淘汰最久未使用的键2put(cache, 4, 400);// 获取值printf("获取键1的值:%d\n", get(cache, 1));  // 输出100printf("获取键2的值:%d\n", get(cache, 2));  // 输出-1(键2被淘汰)printf("获取键3的值:%d\n", get(cache, 3));  // 输出300printf("获取键4的值:%d\n", get(cache, 4));  // 输出400// 释放LRU缓存freeLRUCache(cache);return 0;
}

在上面的代码中,我们首先初始化一个LRU缓存,然后插入键值对 (1, 100)(2, 200)(3, 300)。接着,通过调用 get() 函数获取这些键的值。在插入新键值对 (4, 400) 后,最久未使用的键 (2, 200) 被淘汰。因此,再次获取键 2 的值时,将返回 -1

总结

LRU缓存是一种基于双向链表和哈希表的数据结构,用于管理缓存中的数据并自动淘汰最近最少使用的数据。它通过高效的插入、访问和删除操作,提高了应用程序的性能。LRU缓存非常适合用于对数据访问频率

较高且具有较强时效性的数据集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/1550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《深入浅出.NET框架设计与实现》笔记1——.NET CLI 概述

.NET CLI&#xff08;NET 命令行接口&#xff09;工具是用于开发生成运行和发布.NET应用程序的跨平台工具链。 一、CLI命令 默认安装的命令有 1、基本命令 new restore build publish run test vstest pack migrate clean sln help store 2、项目修改命令 add package add …

使用easyexcel将csv转为excel

一.背景 供应商系统下载的csv文件不支持域控&#xff08;主要是第三方wps服务不能对csv文件加密&#xff0c;但是可以对office系列产品进行权限访问的加密控制&#xff09;。因此思路就改为现将csv文件转为excel文件&#xff0c;然后对excel文件进行加域控制。本文主要介绍如何…

12.Hexo helpers类似函数和data folder数据文件夹

helper Hexo里的helper&#xff0c;或者说是函数 基本上就是小函数&#xff0c;可以在layout布局中使用&#xff0c;可以允许做一些事情 如字符串操作、检查true或false、检查是否在一个页面上、打印出某个页面中的日期或时间特定格式 打开index.ejs trim 可以通过 <%…

向量数据库的崛起:如何改变数据存储与机器学习的未来

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

ExpertPrompting:指导大语言模型成为杰出专家

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 论文标题&#xff1a;ExpertPrompting: Instructing Large Language Models to be Distinguished Experts 论文地址&#xff1a;https://arxiv.org/abs/2305.14688 作者 & 机构&#xff1a;Benfen…

金融领域思考-前言

1背景介绍 不知不觉已经进入金融领域并且从事支付相关研发工作2年&#xff0c;2年了&#xff0c;应该是一个非常重要的分水岭。但越学习&#xff0c;越了解&#xff0c;越知道金融领域的复杂性。故希望借助写博客整理相关思绪&#xff0c;每有会意&#xff0c;便会记录&#x…

3.车载网络诊断测试用例标准与示例(车载网络诊断测试平台)

文章目录 1.概述2.测试用例2.1 用例名字2.2 用例ID2.3 测试需求来源2.4 测试环境2.5 测试目的2.6 前提条件2.7 手动/自动2.8 测试步骤2.9 评价标准2.10 备注2.11 测试结果2.12 测试数据3.测试用例示例4.其他1.概述

Linux嵌入式驱动开发-阻塞IO与非阻塞IO

文章目录 阻塞与非阻塞访问简介阻塞访问的实现等待队列等待队列头等待队列项从等待队列头添加/移除等待队列项等待唤醒等待事件API 非阻塞访问的实现轮询poll 函数原型可以返回的资源状态 阻塞与非阻塞访问简介 **IO&#xff1a;**Input/Output&#xff0c;也就是输入/输出&am…

环境感知——自动驾驶模型训练(菜鸟版本)

简述 本文用仿真工具录制下训练数据后&#xff0c;存到本地CSV文件中&#xff0c;本文仅用方向盘转角速度进行训练。 代码示例采用Jupyter编码&#xff0c;如在其他编辑器运行问题&#xff0c;请使用Jupyter. CSV文件中存储的数据如下&#xff1a; "center",&quo…

Mysql学习大纲

文章目录 整体大纲总结 整体大纲 大纲 MySQL在金融互联网行业的企业级安装部署mysql启动关闭原理和实战&#xff0c;及常见错误排查 花钱9.9 订阅了专栏MySQL字符集和校对规则史上最详细的Mysql用户权原理和实战&#xff0c;生产案例InnoDB引擎原理和实战&#xff0c;通俗易懂…

IoT、IIoT、AIoT的区别是什么?

一、IoT、IIoT、AIoT的区别是什么&#xff1f; IoT、IIoT和AIoT都是物联网&#xff08;Internet of Things&#xff09;的不同应用和发展方向&#xff0c;但它们之间存在一些区别。 IoT&#xff08;物联网&#xff09;&#xff1a;物联网是指通过互联网连接各种物理设备&#x…

Arcgis 定义投影、投影变换、导出栅格为tif

目录 一、Arcgis 定义投影 1、定义投影 2、设置平移 二、投影变换 1、栅格数据的投影变换 2、矢量数据的投影变换

【Linux】小知识点温习---命令

许多常见命令会用&#xff0c;但是很少注意他们的区别&#xff1b;亦或在学习中使用较少&#xff0c;容易忘记&#xff0c;今天做一个回顾。 ls系列 -a:显示所有文件&#xff08;包括隐藏文件&#xff09; -l:将文件以竖列形式显示 -i&#xff1a;显示文件的inode编号 pwd 显…

MacOS 文件系统种类及介绍

MacOS 文件系统种类 详细介绍 详细介绍 从图片中我们可以看到一个文件系统选择器的界面&#xff0c;列出了多种不同的文件系统选项。这些文件系统各有其特点和用途&#xff0c;以下是它们之间的主要区别&#xff1a; APFS&#xff1a;Apple File System&#xff0c;是苹果公司为…

车载电子电器架构 —— 功能安全开发(首篇)

车载电子电器架构 —— 功能安全开发 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

2.2 海思SS928开发 - 编译测试 - kernel

2.2 编译测试 - kernel 创建仓库 在 gitlab 上创建 SS928 kernel 仓库&#xff0c;并命名为 SS928_KERNEL_V4.19。 进入开发虚拟机&#xff0c;克隆仓库&#xff1a; cd ~ mkdir -p hiss928/kernel && cd hiss928/kernel git clone http://gitlab.xxx.com/KERNEL/SS9…

acwing算法提高之图论--欧拉回路和欧拉路径

目录 1 介绍2 训练 1 介绍 本专题用来记录欧拉回路和欧拉路径相关的题目。 相关结论&#xff1a; &#xff08;1&#xff09;对于无向图&#xff0c;所有边都是连通的。 &#xff08;1.1&#xff09;存在欧拉路径的充要条件&#xff1a;度数为奇数的结点只能是0个或者2个。 &…

江西智博环境| 邀您参加2024全国水科技大会暨技术装备成果展览会

展位号&#xff1a;A28 企业介绍 江西智博环境技术有限公司始创于2008年初&#xff0c;总部位于江西省域副中心城市-赣州。公司主要从事一体化净水设备、单村供站、泵船、无负压供水设备自动化控制系统、低配电系统、工艺设备及智慧水务的设计研发、生产、销售、安装、调试等业…

kubeadm 升级 k8s集群 1.17到1.20

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes 基础学习 系列文章&#xff0c;主要讲解 使用kubeadm&#xff0c;将kubernetes集群从1.17升级到1.20 1.kubernetes一般不要跨大版本升级 一般来说&#xff0c;跨越多个主要版本的升级需要逐个升级每…

WordPress SQLite Docker 镜像封装细节

为了让大家用的放心&#xff0c;同时解答 GitHub 社区中的疑问。这篇文章聊聊上一篇文章的 Docker 容器封装细节。 写在前面 在前一篇文章《WordPress 告别 MySQL&#xff1a;Docker SQLite WordPress》中&#xff0c;如果你跟着文章实践&#xff0c;大概三分钟就能够启动一个…