算法 —— LRU算法

算法 —— LRU算法

  • LRU
      • LRU算法的工作原理:
      • 實現方法:
      • 性能考慮:
  • 模擬過程
    • splice函數
      • 對于`std::list`和`std::forward_list`
        • 基本語法:
        • 功能描述:
      • 示例:
      • 注意事項:

如果大家已經學習過了Cache的替換算法和頁面置換算法,大家一定對LRU(Least Recently Used,最近最少使用)不陌生,我們今天來研究下這個算法:

https://leetcode.cn/problems/lru-cache/description/

在這里插入圖片描述這里有一個例子:
在這里插入圖片描述

LRU

LRU(Least Recently Used,最近最少使用)算法是一種常用的緩存淘汰策略,用于在緩存空間有限的情況下決定哪些數據應該被保留,哪些數據應該被移除LRU算法的基本理念是:如果某數據在最近一段時間內沒有被訪問,那么在未來被訪問的可能性也比較低。反之,如果某數據被頻繁訪問,那么它應當被保留在緩存中

LRU算法的工作原理:

  1. 緩存初始化:當緩存初始化時,它是空的。
  1. 數據訪問
  • 如果請求的數據已經在緩存中,稱為緩存命中(Hit),則更新該數據項的訪問狀態,表明它最近被使用過。
  • 如果請求的數據不在緩存中,稱為緩存未命中(Miss),則需要從主存或其他存儲中加載數據到緩存。
  1. 數據淘汰
  • 當緩存已滿,而新的數據需要加入緩存時,LRU算法會選擇最近最少使用的數據項進行淘汰,以便為新數據騰出空間。
  • “最近最少使用”的定義是:在當前時刻,從上次訪問到現在時間間隔最長的數據。

實現方法:

LRU算法可以通過多種數據結構來實現,其中最常見的是使用雙向鏈表和哈希表的組合:

  • 雙向鏈表:用于維護數據項的訪問順序,最新訪問的數據放在鏈表頭部,最久未訪問的數據放在鏈表尾部。
  • 哈希表:用于快速查找數據項在雙向鏈表中的位置。

當數據被訪問時,它從鏈表中的當前位置移動到鏈表頭部。當緩存滿時,鏈表尾部的數據項被移除。

性能考慮:

LRU算法雖然直觀且有效,但在某些情況下可能會有性能開銷,尤其是當數據集非常大時,維護鏈表的插入和刪除操作可能會成為瓶頸。此外,如果數據訪問模式中存在大量突發性的隨機訪問,LRU算法可能無法很好地預測哪些數據是真正需要保留在緩存中的。

盡管如此,LRU仍然是許多緩存系統中首選的淘汰策略,因為它在大多數情況下能夠提供較好的命中率和性能。在軟件和硬件緩存管理中,LRU算法都有廣泛應用。例如,在Web服務器緩存、數據庫查詢緩存、CPU緩存和虛擬內存管理系統中都能見到它的身影。

模擬過程

我們這里用unordered_map和list來模擬:

#pragma once
#include<iostream>
#include<unordered_map>
#include<list>
using namespace std;class LRUCache {
public:LRUCache(int capacity) {}int get(int key) {}void put(int key, int value) {}private:size_t _capacity; //容量//查詢unordered_map<int ,list<pair<int,int>>::iterator> _LRUMap;//插入刪除list<pair<int, int>> _LRUList;
};

unordered_map可以幫助我們查詢是O(1)的時間復雜度,list幫助我們模擬過程,這里我們unordered_map的第二個鍵值對是list的迭代器,這個方便我們直接修改順序是O(1)的操作:

我們來看看:
在這里插入圖片描述我們按照這個過程來模擬:

LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 緩存是 {1=1}
lRUCache.put(2, 2); // 緩存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 該操作會使得關鍵字 2 作廢,緩存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 該操作會使得關鍵字 1 作廢,緩存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4

在這里插入圖片描述
在這里插入圖片描述
這個時候執行了查詢操作:

lRUCache.get(1);    // 返回 1

在這里插入圖片描述接下來我們放入了3,3:

lRUCache.put(3, 3); // 該操作會使得關鍵字 2 作廢,緩存是 {1=1, 3=3}

在這里插入圖片描述
以此類推,我們可以得出代碼:

#pragma once
#include <iostream>
#include <unordered_map>
#include <list>
using namespace std;class LRUCache {
public:// 構造函數,初始化緩存容量LRUCache(int capacity) : _capacity(capacity) {}// 獲取緩存中的值,如果存在則更新其位置至最近使用int get(int key) {// 查找鍵值對應的迭代器auto ret = _LRUMap.find(key);if (ret != _LRUMap.end()) { // 如果找到了鍵值list<pair<int, int>>::iterator it = ret->second;// 將找到的元素移動到列表的前端,表示最近被使用_LRUList.splice(_LRUList.begin(), _LRUList, it);// 返回值return it->second;} else {// 如果沒有找到,返回-1return -1;}}// 插入或更新鍵值對void put(int key, int value) {// 查找鍵值對應的迭代器auto ret = _LRUMap.find(key);if (ret == _LRUMap.end()) { // 如果沒找到,即鍵值不存在// 如果緩存已滿if (_capacity == _LRUList.size()) {// 刪除最舊的元素(列表的最后一個元素)_LRUMap.erase(_LRUList.back().first);_LRUList.pop_back();}// 插入新的鍵值對到列表前端_LRUList.push_front(make_pair(key, value));// 更新或添加鍵值對應的迭代器到哈希表_LRUMap[key] = _LRUList.begin();} else {// 如果鍵值已存在,更新值并移動到列表前端list<pair<int, int>>::iterator it = ret->second;it->second = value; // 更新值// 將元素移動到列表前端_LRUList.splice(_LRUList.begin(), _LRUList, it);}}// 打印緩存內容void Print() {for (auto e : _LRUList) {cout << "key值: " << e.first << " value值: "<< e.second << endl;}cout << endl;}private:size_t _capacity; // 緩存的最大容量// 用于快速查找鍵值對應的迭代器unordered_map<int, list<pair<int, int>>::iterator> _LRUMap;// 存儲鍵值對的有序列表,用于維護最近使用的順序list<pair<int, int>> _LRUList;
};

在這里插入圖片描述在這里插入圖片描述

splice函數

splice是C++標準模板庫(STL)中容器(如std::list, std::forward_list, std::deque)的一個成員函數,用于在容器之間或容器內部移動元素。splice函數允許你將一個容器中的元素或一組連續的元素無縫地插入到另一個相同類型的容器的指定位置,而無需復制或構造元素。這對于需要高效地重新組織元素順序的情況非常有用。

對于std::liststd::forward_list

對于std::liststd::forward_listsplice的用法如下:

基本語法:
void splice(position, x);
void splice(position, x, iterator i);
void splice(position, x, iterator first, iterator last);
  • position:在當前容器中插入元素的位置,對于std::list,可以是iteratorconst_reference;對于std::forward_list,總是before_begin()
  • x:源容器,必須與當前容器具有相同的類型。
  • i:源容器中的單個元素迭代器。
  • first, last:源容器中元素范圍的迭代器。
功能描述:
  • splice(position, x);:將x容器中的所有元素移動到當前容器的position位置之前。
  • splice(position, x, i);:將x容器中由i指向的單個元素移動到當前容器的position位置之前。
  • splice(position, x, first, last);:將x容器中由[first, last)區間定義的元素序列移動到當前容器的position位置之前。

示例:

假設我們有兩個std::list<int>容器,list1list2,我們想把list2中的元素5移動到list1的開始位置:

std::list<int> list1{1, 2, 3, 4};
std::list<int> list2{5, 6, 7, 8};auto it = list2.find(5);
list1.splice(list1.begin(), list2, it);

現在list1看起來應該是{5, 1, 2, 3, 4},而list2應該是{6, 7, 8}

注意事項:

  • 移動操作是常數時間復雜度的,因此splice非常高效。
  • 被移動的元素將從源容器中移除。
  • 如果兩個容器共享同一個分配器(例如,它們是同一個容器的不同部分),splice操作不會拋出異常。

對于std::dequesplice的用法與上述略有不同,因為std::deque不允許在中間插入或刪除元素,只能在兩端進行。因此,std::dequesplice只接受before_begin()end()作為插入位置,而且只能從另一個std::deque中移動元素到當前std::deque的開頭或結尾。

總之,splice是一個強大的工具,可以高效地重新組織容器中的元素,特別是在需要移動大量元素或避免不必要的元素復制時。

具體更多的可以查看官網:

https://legacy.cplusplus.com/

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/46246.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/46246.shtml
英文地址,請注明出處:http://en.pswp.cn/web/46246.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ElementUIV12相關使用方法

今日內容 零、 復習昨日 零、 復習昨日 一、Element UI Element&#xff0c;一套為開發者、設計師和產品經理準備的基于 Vue 2.0 的桌面端組件庫 官網&#xff1a; https://element.eleme.cn/#/zh-CN Element Plus,基于 Vue 3&#xff0c;面向設計師和開發者的組件庫 官網: htt…

C語言--遞歸

曾經有一個段子&#xff1a;上大學時&#xff0c;我們的c語言老師說&#xff1a;學c時&#xff0c;如果有50%的同學死在了循環上面&#xff0c;那么就有90%的同學死在了遞歸上面。接下來&#xff0c;就來看看遞歸是怎么個事&#xff1f; 一.遞歸的介紹 遞歸是指一個函數直接或…

Spring中的@Transactional什么時候會失效?

在Spring中&#xff0c;Transactional注解用于聲明式事務管理&#xff0c;它可以使方法在事務上下文中執行。然而&#xff0c;Transactional注解有時會失效&#xff0c;這通常是由于以下幾種情況&#xff1a; 1. 非public方法&#xff1a; - Transactional注解默認只能應用…

跨平臺WPF音樂商店應用程序

目錄 一 簡介 二 設計思路 三 源碼 一 簡介 支持在線檢索音樂&#xff0c;支持實時瀏覽當前收藏的音樂及音樂數據的持久化。 二 設計思路 采用MVVM架構&#xff0c;前后端分離&#xff0c;子界面彈出始終位于主界面的中心。 三 源碼 視窗引導啟動源碼&#xff1a; namesp…

MySQL(8)事務

目錄 1.事務; 1.事務: 1.1 如果CURD不加限制會這么樣子? 可能造成數據同時被修改, 數據修改的結果是未知的.(可以想一下之前的搶票線程問題) 1.2 事務概念: 事務就是一組DML語句組成&#xff0c;這些語句在邏輯上存在相關性&#xff0c;這一組DML語句要么全部成功&#xff0…

基于python旅游景點滿意度分析設計與實現

1.1研究背景與意義 1.1.1研究背景 隨著旅游業的快速發展&#xff0c;滿意度分析成為評估旅游景點質量和提升游客體驗的重要手段。海口市作為中國的旅游城市之一&#xff0c;其旅游景點吸引了大量游客。然而&#xff0c;如何科學評估和提升海口市旅游景點的滿意度&#xff0c;…

中電金信-杭州工商銀行|面試真題|2024年

中電金信-杭州工商銀行 JAva集合用過哪些? ArrayList、LinkedList、HashSet、TreeSet、HashMap、LinkedHashMap、ConcurrentHashMap Arraylist和linkbist區別 ArrayList底層是數據&#xff0c;查詢快&#xff0c;增刪慢&#xff0c;線程不安全&#xff0c;效率高LikedList 底…

【概率論三】參數估計:點估計(矩估計、極大似然法)、區間估計

文章目錄 一. 點估計1. 矩估計法2. 極大似然法2.1. 似然函數2.2. 極大似然估計法 3. 評價估計量的標準3.1. 無偏性3.2. 有效性3.3. 一致性 二. 區間估計1. 區間估計的概念2. 正態總體參數的區間估計 參數估計講什么 由樣本來確定未知參數參數估計分為點估計與區間估計 一. 點估…

算法:二叉樹相關

目錄 題目一&#xff1a;單值二叉樹 題目二&#xff1a;二叉樹的最大深度 題目三&#xff1a;相同的樹 題目四&#xff1a;對稱二叉樹 題目五&#xff1a;另一棵樹的子樹 題目六&#xff1a;二叉樹的前序遍歷 題目七&#xff1a;二叉樹遍歷 題目八&#xff1a;根據二叉…

linux搭建mysql主從復制(一主一從)

目錄 0、環境部署 1、主服務器配置 1.1 修改mysql配置文件 1.2 重啟mysql 1.3 為從服務器授權 1.4 查看二進制日志坐標 2、從服務器配置 2.1 修改mysql配置文件 2.2 重啟mysql 2.3 配置主從同步 2.4 開啟主從復制 3、驗證主從復制 3.1 主服務器上創建test…

微服務拆分流程 (黑馬商城拆分商品服務)

1. 創建新module - maven模塊&#xff0c;并引入依賴&#xff08;可以復制 把不需要的依賴刪掉 &#xff09; 2. 新建包com.hmall.xx&#xff08;業務名&#xff09;&#xff0c;添加和修改啟動類&#xff0c;新建mapper包、domain包 - service包 - controller包 3. 拷貝并修…

4款良心軟件,免費又實用,內存滿了都舍不得卸載

以下幾款高質量軟件&#xff0c;若是不曾體驗&#xff0c;實在是遺憾可惜。 PDF Guru 這是一款開源免費的PDF編輯軟件&#xff0c;打開之后功能一目了然。 可以拆分、合并PDF&#xff0c;也可以給PDF添加水印和密碼&#xff0c;同時也可以去除別人PDF里的水印或密碼&#xff0…

HouseCrafter:平面草稿至3D室內場景的革新之旅

在室內設計、房地產展示和影視布景設計等領域,將平面草稿圖快速轉換為立體的3D場景一直是一個迫切的需求。HouseCrafter,一個創新的AI室內設計方案,正致力于解決這一挑戰。本文將探索HouseCrafter如何將這一過程自動化并提升至新的高度。 一、定位:AI室內設計的革新者 Ho…

Scala之OOP講解

Scala OOP 前序 Scala 為純粹OOP1、不支持基本類型&#xff1a;一切皆為對象 Byte,Int,...2、不支持靜態關鍵字&#xff1a;static 3、支持類型推斷【通過判斷泛型的父子關系來確定泛型類的父子關系>協變&#xff0c;逆變&#xff0c;不變】和類型預定&#xff0c; 動靜…

【iOS】類對象的結構分析

目錄 對象的分類object_getClass和class方法isa流程和繼承鏈分析isa流程實例驗證類的繼承鏈實例驗證 類的結構cache_t結構bits分析實例驗證屬性properties方法methods協議protocolsro類方法 類結構流程圖解 對象的分類 OC中的對象主要可以分為3種&#xff1a;實例對象&#xf…

【React】JSX基礎

一、簡介 JSX是JavaScript XML的縮寫&#xff0c;它是一種在JavaScript代碼中編寫類似HTML模板的結構的方法。JSX是React框架中構建用戶界面&#xff08;UI&#xff09;的核心方式之一。 1.什么是JSX JSX允許開發者使用類似HTML的聲明式模板來構建組件。它結合了HTML的直觀性…

TDesign組件庫日常應用的一些注意事項

【前言】Element&#xff08;餓了么開源組件庫&#xff09;在國內使用的普及率和覆蓋率高于TDesign-vue&#xff08;騰訊開源組件庫&#xff09;&#xff0c;這也導致日常開發遇到組件使用上的疑惑時&#xff0c;網上幾乎搜索不到其文章解決方案&#xff0c;只能深挖官方文檔或…

2024.7.17 ABAP面試題目總結

2024.7.17 用的SAP什么平臺&#xff0c;S4/HANA嗎&#xff0c;有用過ECC嗎 S4/HANA&#xff0c;沒用過ECC 會不會CDS VIEW 不會 會不會FIORI 不會 銀企直連里面的邏輯了解不 不了解&#xff0c;做過&#xff0c;但是只能算很簡單的修改 SAP做增強&#xff0c;如何創建…

網絡安全-網絡安全及其防護措施7

31.防病毒和惡意軟件保護 防病毒和惡意軟件防護的定義和作用 防病毒和惡意軟件防護是一種保護計算機和網絡免受病毒、木馬、間諜軟件等惡意軟件侵害的安全措施。通過防護措施&#xff0c;可以檢測、阻止和清除惡意軟件&#xff0c;確保系統和數據的安全。其主要作用包括&…

C++右值引用和移動語義

目錄 概念&#xff1a; 左值引用和右值引用 概念&#xff1a; 注意&#xff1a; 左值引用的意義 作函數參數 函數引用返回 右值引用的意義 誕生背景 移動構造 移動賦值 其他應用 萬能引用和完美轉發 默認的移動構造和移動賦值 概念&#xff1a; 左值&#xff1a;顧…