9.16日常记录

news2024/11/14 12:12:28

1.LRU算法

核心思想:LRU算法(Least Recently Used)是一种常用的缓存淘汰策略,它的核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。LRU算法主要用于内存管理和缓存系统。当内存或缓存空间已满,需要腾出空间时,LRU算法会选择最近最久未使用的数据进行淘汰。

2.LRU算法的基本原理

LRU算法的基本原理是跟踪数据的访问时间,并在需要淘汰数据时选择最久未使用的数据。在实现上,最常见的方法是使用一个链表来保存缓存数据。新数据插入到链表头部,每当缓存命中(即缓存数据被访问),则将数据移到链表头部。当链表满的时候,将链表尾部的数据丢弃。

3.LeetCode中的实现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) 的平均时间复杂度运行。

 1.首先我的想法是通过哈希表和双链表来实现,双链表负责节点的移动,哈希表负责快速定位节点。

struct LinkedNode{//自定义双链表
    int key,value;
    LinkedNode* prev;//前驱节点
    LinkedNode* next;//后继结点
    LinkedNode():key(0),value(0),prev(nullptr),next(nullptr){}
    LinkedNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){}
};

定义了一个双链表结构体,并定义了前驱节点和后继节点,双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的

在LRU的类中,我定义了虚拟的头尾节点,这样在添加节点和删除节点的时候就不需要检查相邻的节点是否存在了。

  unordered_map<int,LinkedNode*> cache;
    LinkedNode* head;//首部
    LinkedNode* tail;//尾部
    int size;
    int capacity;

 之后,我定义了函数的有参构造,并让首尾指针互相指向。

 LRUCache(int _capacity):capacity(_capacity),size(0) {//有参构造
        //使用伪头部和伪尾部节点
        head=new LinkedNode();
        tail=new LinkedNode();
        head->next=tail;
        tail->prev=head;
    }

 之后就是get函数了,题目描述如:如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 ;所以可以通过哈希表自带的函数count来检验key是否存在于哈希表中(时间复杂度0(1))

如果存在的话,因为LRU的特性(将最近访问的节点放到头部,最久不访问的放在尾部),就将node节点移动到头结点。

   int get(int key) {
       if(!cache.count(key)){//用于检查某一个值是否存在
        return -1;
       }
       //如果key存在 先通过哈希表定位 再移动到头部
       LinkedNode* node=cache[key];
       moveToHead(node);//移动到头部**
       return node->value;
    }

 put的题目描述如下:

void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。

向其中插入数据,如果不存在,就将其添加到哈希表<值,双链表指针>,并且放在头部,并判断此时的容量是否大于最大容量,若大于,淘汰尾部节点,并将节点对应的值从哈希表中移除。

如果存在,先根据key从哈希表中对应处节点,然后修改节点对应的值,最后将节点移动到头部。 

 void put(int key, int value) {
        if(!cache.count(key)){//用于检查某一个值是否存在
        //不存在
       LinkedNode* node=new LinkedNode(key,value);
        cache[key]=node;//添加到哈希表
             addToHead(node);        //添加到头部
            ++size;
            if(size>capacity){
                LinkedNode* removed=removeTail();
                cache.erase(removed->key);
                delete removed;
                --size;
            }
       }else{
            //如果key存在 先通过哈希表定位 在修改value,并且移动到头部
                LinkedNode* node=cache[key];
                node->value=value;
                moveToHead(node);
       }
    }

 最后就是定义移动节点的成员函数:

函数涉及到双指针的修改和插入操作,第一次我干看代码也没理解,知道画图出来才明白;

 理解了如何添加节点之后,下面的也就难度不大了,要注意的一点是,在moveToHead函数中,不能改变俩个函数的位置,因为如果改变之后,就会报错内存错误--在释放堆内存之后继续使用。这是因为节点被错误地添加到头部后,又在未正确处理的情况下被删除。

void addToHead(LinkedNode* node){//添加到头结点
        node->prev=head;
        node->next=head->next;
        head->next->prev=node;
        head->next=node;
}

void removeNode(LinkedNode* node){//移除节点
        node->prev->next=node->next;//双链表的删除方法
        node->next->prev=node->prev;
}
void moveToHead(LinkedNode* node){//移动到头结点
        removeNode(node);
        addToHead(node);
      
}
LinkedNode* removeTail(){//移除尾节点
        LinkedNode* node=tail->prev;
        removeNode(node);
        return node;
}

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

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

相关文章

【工具变量】气候适应型试点城市DID(2005-2022年)

数据来源&#xff1a;本数据来源于中国ZF网发布的《关于深化气候适应型城市建设试点的通知》 时间跨度&#xff1a;2005-2022年数据简介&#xff1a;适应型试点城市是指在应对气候变化、提高城市适应能力方面进行先行先试的城市。根据中国ZF网发布的《关于深化气候适应型城市建…

在 Stable Diffusion 1.5 中 Lora, Dreambooth, Textual Inversion的详解指北

Lora, Dreambooth and Textual Inversion 说明 您是否想象过您可爱的宠物与埃菲尔铁塔合影的画面&#xff0c;或者想象过如何生成一张带有您朋友面孔的人工智能图像&#xff1f; 是的&#xff0c;通过稳定扩散技术的微调&#xff0c;这完全是可能的&#xff01; 创建这些场景…

NISP 一级 | 7.2 信息安全风险管理

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 0x01&#xff1a;信息安全风险 信息系统不可能达到绝对安全&#xff0c;但可以通过安全风险&#xff08;以下简称“风险”&#xff09;控制来实现符合个人或单位目标的一定程度的安全。信息安全管…

xxl-job、Quartz、power-job、elastic-job对比选型

一、框架对比 1. Quartz 优点&#xff1a;稳定性和可扩展性好&#xff0c;适用于企业级应用&#xff1b;调度功能丰富&#xff0c;满足多种需求。 缺点&#xff1a;本身不提供原生的分布式支持&#xff0c;需要通过扩展或与其他组件结合来实现分布式任务调度&#xff1b;调度…

树莓派驱动之spi回环测试

开启spi sudo raspi-config选择Interfacing options,选择spi打开 lsmod可以看到spi_bcm2835 短接MISO和MOSI 编写回环代码spitest.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h>…

第六部分:1---进程间通信,匿名管道

目录 进程间通信 进程间通信的目的&#xff1a; 进程间通信的本质&#xff1a; 管道&#xff1a; 管道的定义&#xff1a; 匿名管道 单向通信的管道通路&#xff1a; 进程和文件之间的解耦&#xff1a; 单向管道的读写端回收问题&#xff1a; 管道通信主要实现动态数…

Python VS Golng 谁更胜一筹?

今天我们聊聊Python和Golang这俩到底谁更胜一筹。 这个话题我已经在各种技术论坛上看到无数次了&#xff0c;每次都能引起一波热烈的讨论。作为一个多年写代码的老程序员&#xff0c;今天就站在我的角度&#xff0c;和大家掰扯掰扯这两个语言各自的优缺点。 1. 性能与并发模型…

283. 移动零(快慢指针)

算法分析&#xff1a; 如果数组没有0&#xff0c;快慢指针同步移动&#xff0c;元素会被自己复制&#xff1b;如果有0&#xff0c;快指针找到非零元素&#xff0c;将其复制到慢指针位置最终将剩余位置填充为0。 代码&#xff1a; class Solution {public void moveZeroes(i…

Android Studio 2024 安装、项目创建、加速、优化

文章目录 Android Studio安装Android Studio项目创建Android Studio加速修改GRADLE_USER_HOME位置减少C盘占用空间GRADLE加速 修改模拟器位置减少C盘占用空间参考资料 Android Studio安装 下载android studio download android-studio-2024.1.2.12-windows.exe 或者 android-…

11 - TCPClient实验

在上一个章节的UDP通信测试中&#xff0c;尽管通信的实现过程相对简洁&#xff0c;但出现了通信数据丢包的问题。因此&#xff0c;本章节将基于之前建立的WIFI网络连接&#xff0c;构建一个基础的TCPClient连接机制。我们利用网络调试助手工具来发送数据&#xff0c;测试网络通…

[PICO VR眼镜]眼动追踪串流Unity开发与使用方法,眼动追踪打包报错问题解决(Eye Tracking/手势跟踪)

前言 最近在做一个工作需要用到PICO4 Enterprise VR头盔里的眼动追踪功能&#xff0c;但是遇到了如下问题&#xff1a; 在Unity里面没法串流调试眼动追踪功能&#xff0c;根本获取不到Device&#xff0c;只能将整个场景build成APK&#xff0c;安装到头盔里&#xff0c;才能在…

【技术解析】消息中间件MQ:从原理到RabbitMQ实战(深入浅出)

文章目录 【技术解析】消息中间件MQ&#xff1a;从原理到RabbitMQ实战(深入浅出)1.简介1.1 什么是消息中间件1.2 传统的http请求存在那些缺点1.3 Mq应用场景有那些1.4 为什么需要使用mq1.5 Mq与多线程之间区别1.6 Mq消息中间件名词1.7主流mq区别对比1.8 Mq设计基础知识 2.Rabbi…

C++ | Leetcode C++题解之第415题字符串相加

题目&#xff1a; 题解&#xff1a; class Solution { public:string addStrings(string num1, string num2) {int i num1.length() - 1, j num2.length() - 1, add 0;string ans "";while (i > 0 || j > 0 || add ! 0) {int x i > 0 ? num1[i] - 0 …

大数据Flink(一百一十八):Flink SQL水印操作(Watermark)

文章目录 Flink SQL水印操作&#xff08;Watermark&#xff09; 一、为什么要有WaterMark 二、​​​​​​​​​​​​​​Watermark解决的问题 三、​​​​​​​​​​​​​​代码演示 Flink SQL水印操作&#xff08;Watermark&#xff09; 一、​​​​​​​为什么…

【数据结构】数据结构系列学习笔记——导航篇

一&#xff1a;概述 数据结构是计算机科学中的核心概念之一&#xff0c;是优化算法性能和资源利用率的关键。在软件开发和数据处理中&#xff0c;选择合适的数据结构对于算法的效率至关重要。数据结构的选择通常基于数据的使用模式&#xff0c;包括数据元素之间的关系、数据的存…

日志框架的使用

一、日志概述 日志&#xff1a;用来记录程序运行过程中的信息&#xff0c;并可以进行永久存储。 开发过程中可能会出现以下需求&#xff1a; 希望系统能记住某些数据是被谁操作的&#xff0c;比如被谁删除了&#xff1f;想分析用户浏览系统的具体情况&#xff0c;以便挖掘用…

【深度学习】深度学习模型的加密及解密方案及源码

本文摘要 本文主要根据自己遇到的情况,例如:对于yolo或paddle训练的模型文件,对外使用,不想要别人拿到我的模型文件随意乱用,此时就涉及到对模型文件进行加密与解密 深度学习模型的加密保护非常重要,尤其在商业应用场景下。常见的模型加密方法包括模型文件加密、加密硬件…

图像分割基本知识

计算机视觉和图像处理 Tensorflow入门深度神经网络图像分类目标检测图像分割 图像分割 一、目标分割1.1 图像分割的定义1.2 任务类型1.2.1 任务描述1.2.2 任务类型 二、语义分割2.1 FCN网络2.1.1网络结构 2.2 Unet网络 三、UNet案例3.1 数据集获取3.1.1 设置相关信息3.1.2 图像…

nature communications |多层次蛋白质组分析揭示弥漫型和肠型胃癌之间的分子多样性

文章信息 发表期刊&#xff1a;nature communications 发表日期&#xff1a;2023年2月14日 影响因子&#xff1a;14.7 研究背景 胃癌是世界上主要的癌症类型之一。弥漫型胃癌(DGC)和肠型胃癌(IGC)是胃癌(GC)的主要组织学类型&#xff0c;DGC呈分散的细胞组织&#xff0c;黏…

比特币10年价格数据(2014-2024)分析(进阶2_时间序列分析)

数据入口&#xff1a;【每周挑战】比特币10年价格数据可视化和量化分析 - Heywhale.com 本数据集包含 2014 - 2024 的比特币美元价格数据&#xff0c;具体包含比特币每日的开盘价、最高价、最低价、收盘价以及成交量等关键信息。数据说明如下&#xff1a; 字段说明Date日期&a…