LFU算法

2023-10-28

LFU简介

LFU(Least Frequently Used )也是一种常见的缓存算法。
LFU算法的思想是:如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰。

LFU 算法的描述

设计一种缓存结构,该结构在构造时确定大小,假设大小为 K,并有两个功能:

  1. set(key,value):将记录(key,value)插入该结构。当缓存满时,将访问频率最低的数据置换掉。
  2. get(key):返回key对应的value值。

要求以上两个方法的时间复杂度为O(1)的

在这里插入图片描述
其中圆形为小双向链表的节点,有上指针up、下指针down、键值key、数据项value以及出现次数times

class Node
{
public:
	Node(int key, int value, int times)
	{
		this->key = key;
		this->times = times;
		this->value = value;
	}
	int key;
	int value;
	int times;
	Node *up;
	Node *down;
	
};

其中矩形为大双向链表,其中包含两个小双向链表节点的指针,一个表示小双向链表的头,一个表示小双向链表的尾,还有next指针和last指针,分别指向前一级大链表节点和后一级大链表节点。

class NodeList
{
public:
	NodeList(Node *node)
		:head(node)
		, tail(node)
		, last(nullptr)
		, next(nullptr)
	{

	}

	void addNodeFromHead(Node *newHead)
	{
		newHead->down = head;
		head->up = newHead;
		head = newHead;
	}

	bool isEmpty()
	{
		return head == nullptr;
	}

	void deleteNode(Node *node)
	{
		if (head == tail)
		{
			delete head;
			head = nullptr;
			tail = nullptr;
		}
		else
		{
			if (node == head)
			{
				head = node->down;
				head->up = nullptr;
			}
			else if (node == tail)
			{
				tail = node->up;
				tail->down = nullptr;
			}
			else
			{
				node->up->down = node->down;
				node->down->up = node->up;
			}
			node->up = nullptr;
			node->down = nullptr;
			delete node;
		}
	}
	Node *head;
	Node *tail;
	NodeList *last;
	NodeList *next;
	
};

最后使用以上两个结构形成LFU结构

#include <iostream>
#include <unordered_map>

using namespace std;

class LFUCache 
{
public:
	LFUCache(int capacity)
	{
		this->capacity = capacity;
		this->size = 0;
		headList = nullptr;
	}
	void set(int key, int value)
	{
		if (records.find(key) != records.end())
		{
			Node *node = records[key];
			node->value = value;
			node->times++;
			NodeList *curNodeList = heads.at(node);
			move(node, curNodeList);
		}
		else
		{
			// 这种情况应该先删除一个节点,并消除他的影响。
			if (size == capacity)
			{
				Node *node = headList->tail;
				headList->deleteNode(node);
				modifyHeadList(headList);
				records.erase(node->key);
				heads.erase(node);
				size--;
			}
			// 先判断大头是不是空,如果是空,那么新建1的NodeList,如果不是空,那么就判断大头的次数是不是1,如果是1,那么直接加,如果不是1,就新建1的NodeList
			Node *node = new Node(key, value, 1);
			if (headList == nullptr) //第一次加入数据
			{
				headList = new NodeList(node);
			}
			else {
				// 看看已有的最低次数,如果为1,不需要新建,如果不是1就需要新建一个NodeList。
				if (headList->head->times== node->times) 
				{
					headList->addNodeFromHead(node);
				}
				else { // 换头的操作  新建一个1词频的大链表节点
					NodeList *newList = new NodeList(node);
					newList->next = headList;
					headList->last = newList;
					headList = newList;
				}
			}
			// 结构信息的更新
			records[key]= node;
			heads[node] = headList;
			size++;
		}
	}
	void move(Node *node, NodeList *oldNodeList)
	{
		oldNodeList->deleteNode(node);
		// node将会进入到一个新链表中,那么这个新链表的前一个链表是哪个?
		NodeList *preList = modifyHeadList(oldNodeList) ? oldNodeList->last : oldNodeList;//也有可能为空
		NodeList *nextList = oldNodeList->next;//也有可能为空
		if (nextList == nullptr)
		{
			NodeList *newList = new NodeList(node);
			if (preList != nullptr)
			{
				preList->next = newList;
			}
			newList->last = preList;
			if (headList == nullptr)
			{
				headList = newList;
			}
			heads[node] = newList;
		}
		else
		{
			if (nextList->head->times == node->times)
			{
				nextList->addNodeFromHead(node);
				heads[node] = nextList;
			}
			else
			{
				NodeList *newList = new NodeList(node);
				if (preList != nullptr)
				{
					preList->next = newList;
				}
				newList->last = preList;
				newList->next = nextList;
				nextList->last = newList;
				if (headList == nextList)
				{
					headList = newList;
				}
				heads[node] = newList;
			}
		}
	}
	// 只有当一个链表中有一个节点被删除了,才会掉用这个函数
	// 会将该NodeList节点删除
	bool modifyHeadList(NodeList *nodeList)
	{
		if (headList->isEmpty())
		{
			if (headList == nodeList)
			{
				headList = nodeList->next;
				if (headList != nullptr)
				{
					headList->last = nullptr;
				}
			}
			else
			{
				nodeList->last->next = nodeList->next;
				if (nodeList->next != nullptr)
				{
					nodeList->next->last = nodeList->last;
				}
			}
			delete nodeList;
			return true;
		}
		return false;
	}

	int get(int key) 
	{
		if (records.find(key) == records.end()) 
		{
			return -1;  // 标记为不存在
		}
		Node *node = records[key];
		node->times++;
		NodeList *curNodeList = heads[node];
		move(node, curNodeList);   // 	
		return node->value;
	}
private:
	int capacity;							// 最多多少个
	int size;								// 实际有多少个
	unordered_map<int, Node*> records;		// 为了由key找Node 
	unordered_map<Node*, NodeList*> heads;	// 任何一个Node他是属于哪个Nodelist
	NodeList *headList;						// 整个结构中第一个Nodelist是谁,方便快速的删除。并且可以找到整个结构,虽然不是第一个也可以做到
};
int main(int argc, char **argv)
{


	system("pause");
	return EXIT_SUCCESS;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LFU算法 的相关文章

  • java中正则表达式的基本使用

    正则表达式的常用语法 正则在线检验 http tool chinaz com regex 更多地语法可以参考jdk api中的Pattern类 http tool oschina net apidocs apidoc api jdk zh
  • 传导骚扰的一些其他总结

    传导骚扰测试分类 实际上涉及到一款产品时 这个测试需要测哪些物理量 然后需要用到哪些设备 做骚扰测试 不管你是RE 辐射骚扰 还是CE 传导骚扰 核心的设备还是EMI测试接收机 或者是频谱仪 这两种机器测的是我受平端口的内心和外兜底里的电压
  • [Windows] bat查看端口占用命令, 并且关闭对应进程

    找到进程ID netstat ano find 8080 关闭进程 taskkill PID 13340 F

随机推荐

  • Centos7安装Rabbitmq

    一 下载安装包 RabbitMq需要erlang配合 所以需要安装Rabbitmq server和erlang wget http www rabbitmq com releases rabbitmq server v3 5 0 rabbi
  • CVPR 2023

    点击下方卡片 关注 CVer 公众号 AI CV重磅干货 第一时间送达 点击进入 gt 计算机视觉 微信技术交流群 转载自 CSIG文档图像分析与识别专委会 本文简要介绍CVPR 2023录用论文 Turning a CLIP Model
  • JavaWeb基础2——JDBC

    导航 黑马Java笔记 踩坑汇总 JavaSE JavaWeb SSM SpringBoot 瑞吉外卖 SpringCloud SpringCloudAlibaba 黑马旅游 谷粒商城 目录 一 JDBC 1 1 JDBC概述 1 1 1
  • unity编程实践-制作血条

    作业要求 血条 Health Bar 的预制设计 具体要求如下 分别使用 IMGUI 和 UGUI 实现 使用 UGUI 血条是游戏对象的一个子元素 任何时候需要面对主摄像机 分析两种实现的优缺点 给出预制的使用方法 部署工作 IMGUI
  • 同一个界面多个子控制器切换视图

    先看示例 EssenceViewController为父控制器 AllViewController 全部 VideoViewController 视频 VoiceViewController 声音 PictureViewController
  • react点击事件控制div盒子的显示隐藏

    index jsx import React Component from react class show extends Component constructor props super props this state cls pa
  • 智慧教室系统--低碳节能管控系统

    随着全球气候变化的日益严重 环保 节能 低碳已经成为各行各业追求的目标 教育行业也不例外 建设低碳 环保的智慧教室已经成为学校和政府的共同关注点 智慧教室系统的解决方案正是基于此 旨在通过AIOT数字化平台 智慧教室和智能管控等技术手段 实
  • list(链表)——STL

    文章目录 list list构造函数 3 list 赋值和交换 list 大小操作 list 插入和删除 list 数据存取 list反转和排序 list 将数据进行链式存储 链表 list 是一种物理存储单元上非连续的存储结构 数据元素的
  • vue 项目动态引入css(sass)文件(判断后加载对应的 sass 文件)

    vue 项目动态引入css文件 preface 问题 解决方案 preface 最新在写后台 管理 应 业务需求 众多菜单业务中 有个菜单需要独立出来给领导使用 改领导有独特喜欢的颜色格调 快速开发 只是做了菜单的权限控制 然后和样式 控制
  • merge sort 一些变种、应用

    1 逆序对数目 分治公式 总的逆序对个数 前半部分逆序对个数 后半部分逆序对个数 merge时候每取一次后半部分的数 累加一次前半部分剩余的数的个数 int countInvertion vector
  • Android系统_SystemUI_android10_添加控制底部导航栏广播

    一 问题背景 在对于我们一些特殊场景 我们可能不想用户能够操作返回 回到主页 因此就需要我们能够灵活控制底部导航栏的状态 二 添加思路 底部导航栏术语叫做NavigationBar 属于SystemUI 跟顶部状态栏StatusBar属于同
  • idea使用debug如何退出循环

    工作中调试难免会遇到循环 特别是循环读取文本内容的时候 10条还可以 万一文本行数有1万多行 难不成还要挨个的进行debug 这里我们可以直接使用idea的debug选项跳出循环 例如下图 如何直接跳出这个while循环 答案是将光标定位到
  • 华清学习阶段总结

    从七月份入学以来 我已经在华清远见学习了3个周左右了 先后遇见了两个讲师 两个讲师以及班主任老师都很负责 不论是在学习上还是在生活上都有他们和同学们相应的及时的帮助与提醒 班上的学习氛围也很好 很多问题在他们的帮助下都能解决 在c基础的上完
  • DEBUG:Ubuntu中无法打开Appimage文件

    DEBUG Ubuntu中无法打开Appimage文件 问题 解决 问题 无法安装此类型的文件 解决 右击文件属性 更改权限
  • 关于Decision in process状态时间变化的解释

    最近自己的文章出现了decision in process时间变化的现象 便上网查了下 觉得以下这个解释是靠谱的 这是编辑部自动发给编辑的提醒邮件引起的状态变化 编辑部一般要求编辑应在decision in process后5个工作日内给作
  • 大语言模型之六- LLM之企业私有化部署架构

    2023年上半年 广泛使用API 如OpenAI 来创建基于大型语言模型 LLM 的基础设施 极大地塑造了软件领域 LangChain 和LlamaIndex在这一趋势中发挥了重要的作用 2023年下半年LLMOps的运维工作流程中微调 或
  • CNStack 虚拟化服务:实现虚拟机和容器资源的共池管理

    背景 容器无疑已经成为新的云计算基础设施 企业私有云平台的建设重心 正在从虚拟化的计算 存储 网络的建设 转向构建以容器 微服务等为核心的云原生平台 不过值得注意的是 企业 IT 系统在进行容器化改造的过程中 由于历史遗留系统 技术债务 内
  • python如何实现excel中vlookup函数的功能

    可以使用 Python 的 pandas 库来实现 Excel 中的 VLOOKUP 函数的功能 首先 需要使用 pandas read excel 函数读取 Excel 文件 然后使用 pandas DataFrame merge 函数将
  • xcode SRCROOT inherited executable_path

    xcode search paths中总是能看到这些宏定义 他们定义了一些常用的路径信息 具体的信息参考官网 https developer apple com library archive documentation Developer
  • LFU算法

    LFU简介 LFU Least Frequently Used 也是一种常见的缓存算法 LFU算法的思想是 如果一个数据在最近一段时间很少被访问到 那么可以认为在将来它被访问的可能性也很小 因此 当空间满时 最小频率访问的数据最先被淘汰 L