[TypeScript]手撸LFU

[TypeScript]手撸LFU

最近做笔试的时候遇到了要手撸LFU的题目,LFU在vue源码里还是有使用的,例如keep-alive的实现机制就是基于它来搞的。不多说了,直接上代码。

代码

// 双向链表node
class DoubleLinkNode {key: number;val: number;freq: number;prev?: DoubleLinkNode | null;next?: DoubleLinkNode | null;constructor(key, val, freq) {this.freq = freq;this.key = key;this.val = val;}
}// 双向链表
class DoubleLink {size: number;head: DoubleLinkNode | null;tail: DoubleLinkNode | null;constructor() {this.size = 0;this.head = null;this.tail = null;}// 删除一个节点remove(node: DoubleLinkNode) {// 空链表if (this.size < 1) {return;}// 只有一个元素if (this.size === 1) {this.size = 0;this.head = null;this.tail = null;return;}// 删的是头结点if (node === this.head) {const nextNode = node.next;nextNode.prev = null;this.head = nextNode;this.size--;return;}// 删的是尾结点if (node === this.tail) {const prevNode = node.prev;prevNode.next = null;this.tail = prevNode;this.size--;return;}// 正常删中间节点const prevNode = node.prev;const nextNode = node.next;prevNode.next = nextNode;nextNode.prev = prevNode;this.size--;}// 在尾部插入一个节点addLast(node: DoubleLinkNode) {// 空链表if (this.size === 0) {this.head = node;this.tail = node;} else {// 非空链表const curTail = this.tail;curTail.next = node;node.prev = curTail;this.tail = node;}this.size++;}// 是否是空链表isEmpty() {return this.size === 0;}
}// 实现LFU缓存
class LFUCache {keyToNodeMap: Map<number, DoubleLinkNode>;freqToKeysMap: Map<number, DoubleLink>;capacity: number;minFreq: number;constructor(capacity: number) {this.keyToNodeMap = new Map();this.freqToKeysMap = new Map();this.capacity = capacity;this.minFreq = 0;}get(key: number): number {if (!this.keyToNodeMap.has(key)) {return -1;}const node = this.keyToNodeMap.get(key);// 增加频次this.increaseFreq(node);return node.val;}put(key: number, value: number): void {// key已经存在if (this.keyToNodeMap.has(key)) {// 修改对应的node的val即可const node = this.keyToNodeMap.get(key);node.val = value;this.increaseFreq(node);} else {// key不存在// 容量满了if (this.keyToNodeMap.size >= this.capacity) {// 删除最小频次中最久没使用的this.removeMinFreqKey();}// ------------正式开始插入------------const newNode = new DoubleLinkNode(key, value, 1);this.keyToNodeMap.set(key, newNode);if (!this.freqToKeysMap.get(1)) {this.freqToKeysMap.set(1, new DoubleLink());}// 维护频次表const link = this.freqToKeysMap.get(1);link.addLast(newNode);// 插入新 key 后最小的 freq 肯定是 1this.minFreq = 1;}}// 增加频次increaseFreq(node: DoubleLinkNode) {const oldFreq = node.freq;const newFreq = node.freq + 1;node.freq = newFreq;// 维护频次表const oldFreqLink = this.freqToKeysMap.get(oldFreq);// 从旧频次表中删除这个nodeoldFreqLink.remove(node);if (oldFreqLink.isEmpty()) {this.freqToKeysMap.delete(oldFreq);// 如果这个频次正好是最低频次,记得更新最小频次if (this.minFreq === oldFreq) {this.minFreq = newFreq;}}// 维护新频次表if (!this.freqToKeysMap.get(newFreq)) {this.freqToKeysMap.set(newFreq, new DoubleLink());}const newFreqLink = this.freqToKeysMap.get(newFreq);newFreqLink.addLast(node);}// 删除最小频次中最久没使用的removeMinFreqKey() {const minFreqLink = this.freqToKeysMap.get(this.minFreq);// 其中最先被插入的那个 node 就是该被淘汰的 nodeconst deletedNode = minFreqLink.head;// 维护最小频次mapminFreqLink.remove(deletedNode);if (minFreqLink.isEmpty()) {this.freqToKeysMap.delete(this.minFreq);}// key表中删除对应Nodethis.keyToNodeMap.delete(deletedNode.key);}// log调试方法print() {console.log('keyToNodeMap: ', this.keyToNodeMap);console.log('freqToKeysMap: ', this.freqToKeysMap);}
}

思路

LFU(Least Frequently Used)缓存是一种缓存淘汰策略,它根据元素的使用频率来决定哪些元素应该被淘汰。在你提供的代码中,LFUCache 类实现了这种策略,下面是它的工作原理的详细描述:

  1. 数据结构

    • DoubleLinkNode:表示双向链表中的节点,包含键(key)、值(val)和频率(freq)。
    • DoubleLink:表示双向链表,包含头尾节点以及链表的大小。
    • MapkeyToNodeMap 用于存储键到节点的映射,freqToKeysMap 用于存储频率到键的映射。
  2. 构造函数

    • 初始化 LFUCache 时,设置缓存的容量(capacity),并初始化键到节点的映射和频率到键的映射。
  3. get 方法

    • 检查键是否存在于 keyToNodeMap 中。
    • 如果存在,找到对应的节点,并调用 increaseFreq 方法来增加节点的使用频率。
    • 返回节点的值。
  4. put 方法

    • 检查键是否已存在:
      • 如果存在,更新节点的值,并增加频率。
      • 如果不存在,并且缓存已满,则调用 removeMinFreqKey 方法来删除最小频率的键。
    • 创建新节点,并将其添加到 keyToNodeMapfreqToKeysMap 中。
  5. increaseFreq 方法

    • 增加节点的使用频率。
    • 从旧频率的链表中删除节点,并检查是否需要更新最小频率。
    • 将节点添加到新频率的链表中。
  6. removeMinFreqKey 方法

    • 找到最小频率链表的头节点,即最久未使用的节点。
    • 从链表中删除该节点,并更新 freqToKeysMap
    • keyToNodeMap 中删除对应的键。
  7. print 方法

    • 用于调试,打印当前的键到节点映射和频率到键的映射。

这种实现方式确保了:

  • 每个键的使用频率都被跟踪。
  • 当缓存达到容量限制时,最少使用频率的键将被淘汰。
  • 通过双向链表,可以快速地添加和删除节点,同时保持链表的顺序。

这种缓存策略适用于那些需要平衡访问频率和最近使用情况的场景。

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

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

相关文章

阿一课代表今日分享之使用dnscat2 进行dns隧道反弹shell(直连模式linux对linux)

DNS介绍 DNS是域名系统(Domain Name System)的缩写&#xff0c;是因特网的一项核心服务&#xff0c;它作为可以将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串。 DNS的记录类型有很多&a…

归并排序算法Python实现

归并排序原理和步骤 1. 将数组分成两半&#xff0c;直到每个子数组的长度为1 首先&#xff0c;将数组分成两半。如果数组的长度大于1&#xff0c;将其从中间分割为两个子数组。对每个子数组继续进行这个过程&#xff0c;直到每个子数组的长度为1。此时&#xff0c;所有子数组…

L4 Persistence and Streaming

参考自https://www.deeplearning.ai/short-courses/ai-agents-in-langgraph&#xff0c;以下为代码的实现。 这里主要是加入了memory&#xff0c;这样通过self.graph graph.compile(checkpointercheckpointer)就可以加入持久性的检查点通过thread {"configurable"…

项目实战--Spring Boot + GraphQL实现实时数据推送

背景 用户体验不断提升而3对实时数据的需求日益增长&#xff0c;传统的数据获取方式无法满足实时数据的即时性和个性化需求。 GraphQL作为新兴的API查询语言&#xff0c;提供更加灵活、高效的数据获取方案。结合Spring Boot作为后端框架&#xff0c;利用GraphQL实现实时数据推…

Java笔试|面试 —— 对多态性的理解

谈谈对多态性的理解&#xff1a; 一个事物的多种形态&#xff08;编译和运行时状态不一致性&#xff09; 实现机制&#xff1a;通过继承、重写和向上转型&#xff08;Object obj new 子类()&#xff09;来实现。 1.广义上的理解 子类对象的多态性&#xff0c;方法的重写&am…

visual studio 2022 在使用open3d出现的问题及解决方式

当出现以下问题&#xff1a; 使用open3d::utility::LogInfo系列出现LNK2001问题&#xff0c;如下所示&#xff1a;LNK2001 无法解析的外部符号 “char __cdecl fmt::v6::internal::decimal_point_impl(class fmt::v6::internal::locale_ref)” LNK2001 无法解析的外部符号 “p…

【C/C++】SDKDDKVer.h和WinSDKVer.h详解及二者区别

一.SDKDDKVer.h介绍 SDKDDKVer.h 是一个在 Windows 软件开发中常见的头文件&#xff0c;它用于定义软件开发工具包&#xff08;SDK&#xff09;和驱动开发工具包&#xff08;DDK&#xff09;的版本信息。这个文件通常位于 Visual Studio 安装目录下的 Include 子目录中。 …

GD32MCU如何实现掉电数据保存?

大家在GD32 MCU应用时&#xff0c;是否会碰到以下应用需求&#xff1a;希望在MCU掉电时保存一定的数据或标志&#xff0c;用以记录一些关键的数据。 以GD32E103为例&#xff0c;数据的存储介质可以选择内部Flash或者备份数据寄存器。 如下图所示&#xff0c;片内Flash具有10年…

学习数据库的增删改查

一、创建数据库和表 在进行增删改查操作之前&#xff0c;我们需要创建一个数据库和表。 1. 创建数据库 使用 CREATE DATABASE 语句创建数据库&#xff1a; CREATE DATABASE test_db;2. 选择数据库 使用 USE 语句选择数据库&#xff1a; USE test_db;3. 创建表 使用 CREA…

详解C语言结构体

文章目录 1.结构体的声明1.1 结构体的基础知识1.2 结构的声明1.3 结构成员的类型 1.4结构体变量的定义和初始化2.结构体成员的访问3.结构体传参 1.结构体的声明 1.1 结构体的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量 …

【密码学】分组密码概述

一、分组密码的定义 分组密码和流密码都是对称密码体制。 流密码&#xff1a;是将明文视为连续的比特流&#xff0c;对每个比特或字节进行实时加密&#xff0c;而不将其分割成固定的块。流密码适用于加密实时数据流&#xff0c;如网络通信。分组密码&#xff1a;是将明文数据…

【React】Ant Design -- Table分页功能实现

实现步骤 为Table组件指定pagination属性来展示分页效果在分页切换事件中获取到筛选表单中选中的数据使用当前页数据修改params参数依赖引起接口重新调用获取最新数据 const pageChange (page) > {// 拿到当前页参数 修改params 引起接口更新setParams({...params,page})…

翰德恩咨询赋能材料行业上市公司,共筑IPD管理体系新篇章

赋能背景概览 坐落于江苏的某材料行业领军企业&#xff0c;作为国内无机陶瓷膜元件及成套设备领域的佼佼者&#xff0c;以其庞大的生产规模、丰富的产品系列及卓越的研发实力&#xff0c;屹立行业之巅二十余年。公司不仅在新材料研发、技术创新、工艺设计、设备制造及整体解决…

【VUE进阶】安装使用Element Plus组件

Element Plus组件 安装引入组件使用Layout 布局button按钮行内表单菜单 安装 包管理安装 # 选择一个你喜欢的包管理器# NPM $ npm install element-plus --save# Yarn $ yarn add element-plus# pnpm $ pnpm install element-plus浏览器直接引入 例如 <head><!-- I…

Transformer-LSTM预测 | Matlab实现Transformer-LSTM时间序列预测

Transformer-LSTM预测 | Matlab实现Transformer-LSTM时间序列预测 目录 Transformer-LSTM预测 | Matlab实现Transformer-LSTM时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现Transformer-LSTM时间序列预测&#xff0c;Transformer-LSTM&#xf…

浅谈“不要卷模型,要卷应用”

目录 1.概述 2.AI技术应用场景探索 3.避免超级应用陷阱的策略 3.1.追求DAU的弊端 3.2.平衡用户活跃度与应用实用性的策略 4.个性化智能体开发 4.1. 用户需求分析与数据收集 4.2. 技术选择与开发 4.3. 个性化算法设计 4.4. 安全性与隐私保护 4.5. 多渠道集成与响应机…

用vite创建Vue3项目的步骤和文件解释

创建项目的原则是不能出现中文和特殊字符&#xff0c;最好为小写字母&#xff0c;数字&#xff0c;下划线组成 之后在visual studio code 中打开创建的这个项目 src是源代码文件 vite和webpack是有去别的&#xff0c;对于这个vite创建的工程来说index.js是入口文件 在终端里面输…

数字探秘:用神经网络解密MNIST数据集中的数字!

用神经网络解密MNIST数据集中的数字&#xff01; 一. 介绍1.1 MNIST数据集简介1.2 MLP&#xff08;多层感知器&#xff09;模型介绍1.3 目标&#xff1a;使用MLP模型对MNIST数据集中的0-9数字进行分类 二.数据预处理2.1 数据集的获取与加载2.2 数据集的探索性分析&#xff08;E…

骗子用出国月薪3万骗了1000多万上千名求职者被骗

日前,江苏省南通市崇川区人民法院开庭审理了一起涉及诈骗的案件,该案件 审理后引发全国求职者的关注以及热议。根据了解得知,这起案件的主犯是利用出 国劳务的虚假高薪职位位诱饵,最终有上千名求职者被骗上当了。文章来源于&#xff1a;股城网www.gucheng.com 根据法院审…

微信文件太大传不了?学会这些,微信秒变大文件传输神器

在数字化时代&#xff0c;微信已成为我们日常沟通的重要桥梁。然而&#xff0c;当需要在微信上传输大文件时&#xff0c;文件大小的限制往往让人束手无策。 今天&#xff0c;我们将分享一些实用的技巧&#xff0c;帮助你在微信上轻松传输大文件&#xff0c;无论是工作文档还是…