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

LRU缓存算法

LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。

双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。

哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。

#include <iostream>
#include <unordered_map>
using namespace std;

struct ListedNode
{
	int key, value;
	ListedNode* last; // 前趋
	ListedNode* next;  //后继
	ListedNode() :key(0), value(0), last(nullptr), next(nullptr) {  }
	ListedNode(int k, int v) :key(k), value(v), last(nullptr), next(nullptr) { }
};

class LRUCache
{
private:
	unordered_map<int, ListedNode*> cache;
	ListedNode* head;  //头结点
	ListedNode* tail;  //尾节点
	int m_capacity;  // 缓存容量
	int m_size;
public:
	LRUCache(int _capacity) :m_capacity(_capacity), m_size(0)
	{   // 完成初始化
		head = new ListedNode();
		tail = new ListedNode();
		head->next = tail;
		tail->last = head;
	}
	int get(int key)
	{
		if (!cache.count(key)) // 如果不存在key
			return -1;
		// 如果key存在,则将其列为最近使用元素,移动到链表头部
		ListedNode* p = cache[key];
		moveTohead(p);
		return p->value;
	}

	void put(int key, int value)
	{
		if (!cache.count(key))  // 如果key不存在,创建一个新的结点
		{
			ListedNode* node = new ListedNode(key, value);
			// 添加进 哈希表
			cache[key] = node;
			// 更新位置到头部,标注最近使用
			addTohead(node);
			++m_size;
			if (m_size > m_capacity)
			{
				//如果超出容量,删除链表尾部结点
				ListedNode* removed = removeTail();
				//删除哈希表中对应项
				cache.erase(removed->key);
				//防止内存泄漏
				delete removed;
				--m_size;
			}

		}
		else
		{// 如果key存在,先通过哈希表定位,再修改value值,移动到头部
			ListedNode* node = cache[key];
			node->value = value;
			moveTohead(node);
		}
	}

	void addTohead(ListedNode* node)  // 插入节点
	{
		node->last = head;  // 插入结点前趋指向头结点
		node->next = head->next;  //  插入节点后继指向第一个结点
		head->next->last = node; // 头结点的后继指向插入节点
		head->next = node;  // (原)第一个结点的前趋指向插入结点,至此插入完成
	}

	void removeNode(ListedNode* node)  //删除结点
	{
		node->last->next = node->next;
		node->next->last = node->last;
	}

	ListedNode* removeTail()
	{
		ListedNode* p = tail->last;
		removeNode(p);
		return p;
	}

	void moveTohead(ListedNode* node)
	{
		removeNode(node);
		addTohead(node);
	}
};


 

 

相关文章:

  • 判断单链表中是否存在环
  • LeeCode61 旋转链表
  • LeeCode74 搜索二维矩阵
  • (0)Nginx 功能特性
  • (2)nginx 安装、启停
  • (3)nginx 配置(nginx.conf)
  • 汇编语言学习笔记--基础知识篇
  • IAR for 430软件的简单使用
  • 430单片机时钟系统与复位系统的配置(1)
  • 430单片机时钟系统与复位系统的配置(2)
  • STM32F103芯片的一些小知识
  • RCC的一些小知识
  • stm32 SPI学习
  • SPI通信过程以及 STM32的SPI特性构架
  • 通讯的基本概念以及分类
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • IndexedDB
  • LeetCode18.四数之和 JavaScript
  • Linux下的乱码问题
  • Map集合、散列表、红黑树介绍
  • React 快速上手 - 07 前端路由 react-router
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • Redis的resp协议
  • Sequelize 中文文档 v4 - Getting started - 入门
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Webpack 4 学习01(基础配置)
  • 从0实现一个tiny react(三)生命周期
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 浏览器缓存机制分析
  • 入门到放弃node系列之Hello Word篇
  • 十年未变!安全,谁之责?(下)
  • 实习面试笔记
  • 跳前端坑前,先看看这个!!
  • 我与Jetbrains的这些年
  • 学习使用ExpressJS 4.0中的新Router
  • ​比特币大跌的 2 个原因
  • # centos7下FFmpeg环境部署记录
  • #etcd#安装时出错
  • %check_box% in rails :coditions={:has_many , :through}
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (pytorch进阶之路)扩散概率模型
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (生成器)yield与(迭代器)generator
  • (一) storm的集群安装与配置
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • ./和../以及/和~之间的区别
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)...
  • .net6Api后台+uniapp导出Excel
  • .pyc文件还原.py文件_Python什么情况下会生成pyc文件?
  • @AliasFor注解