算法之美:缓存数据淘汰算法分析及分解实现

        在设计一个系统的时候,由于数据库的读取速度远小于内存的读取速度,那么为加快读取速度,需先将一部分数据加入到内存中(该动作称为缓存),但是内存容量又是有限的,当缓存的数据大于内存容量时,就需要删除一部分数据,以加入新的数据。这时候需要设计一种淘汰机制,计算出哪些数据删除,哪些数据保留,常见的淘汰算法有FIFO、LRU、LFU等淘汰算法,接下来我们将一一讲解及实现。

FIFO淘汰算法

        First In First Out,先进先出,淘汰最早被缓存的对象,是一种常用的缓存淘汰算法,它的原理是按照先进先出的原则,当缓存满了之后,先将最早进入缓存的数据淘汰掉,以腾出空间给新的数据,其优点在于实现简单,不需要记录或统计数据的使用次数,只需要记录每个数据进入缓存的时间和每个数据在缓存中的位置即可。
        其缺点也是明显的,它不能有效地淘汰最近最少使用的数据,最近最多使用的数据也可能被淘汰掉,这样就会导致缓存的效率不够高。

public class FIFOCache<K, V> {// 定义缓存的最大容量private  int maxSize;// 定义当前缓存的容量private int curSize;// 用于存放缓存的keyprivate  LinkedList<K> cacheKey;// 用于存放缓存的valueprivate  HashMap<K, V> cacheValue;// 读写锁,保证线程安全private Lock lock = new ReentrantLock();// 构造函数public FIFOCache(int maxSize) {this.maxSize = maxSize;this.curSize = 0;this.cacheKey = new LinkedList<K>();this.cacheValue = new HashMap<K, V>();}// 向缓存插入key-valuepublic void put(K key, V value) {// 加锁保证线程安全lock.lock();try {// 如果缓存已满,则删除最老的keyif (curSize == maxSize) {K oldKey = cacheKey.removeFirst();cacheValue.remove(oldKey);curSize--;}// 插入key-valuecacheKey.addLast(key);cacheValue.put(key, value);curSize++;} finally {// 释放锁lock.unlock();}}// 查询指定key的valuepublic V get(K key) {return cacheValue.get(key);}public void printKeys() {System.out.println(this.cacheKey.toString());}public static void main(String[] args) {FIFOCache cache = new FIFOCache<String, String>(5);cache.put("A", "数据结构篇:深度剖析LSM及与B+树优劣势分析");cache.put("B", "数据结构篇:深度剖析跳跃表及与B+树优劣分析");cache.put("C", "算法之美:堆排序原理剖析及应用案例分解实现");cache.printKeys();cache.put("D", "算法之美:二叉堆原理剖析及堆应用案例讲解及实现");cache.printKeys();Object cacheObj1 = cache.get("A");System.out.println("cacheObj1=" + cacheObj1);Object cacheObj2 = cache.get("C");System.out.println("cacheObj2=" + cacheObj2);}}

LRU最久未使用算法

        Least Recently Used 淘汰算法以时间作为参考,淘汰最长时间未被使用的数据,设计者认为如果数据最近被访问过,那么将来被访问的几率也更高;当内存满后会优先淘汰最长时间没有被使用的元素(都没人要你了,不淘汰你淘汰谁)
        其基本原理就是在缓存满时,将最近最久未使用的数据淘汰出缓存,以便给新的数据留出空间。实现方式可以用:数组、链表等方式,新插入的数据放在头部,最近访问过的也移到头部,空间满时将尾部元素删除。


public class LRUCache {//用于存储key-value数据private HashMap<String, String> map;//用于存储key的顺序private ArrayList<String> list;//数组的容量private int capacity;public LRUCache(int capacity) {this.capacity = capacity;map = new HashMap<>();list = new ArrayList<>();}/*** 查询key对应的value* @param key 键* @return value 值*/public String get(String key) {//如果key存在,则将key移动到最前端if (map.containsKey(key)) {list.remove(key);list.add(0, key);return map.get(key);}return null;}/*** 向缓存中插入key-value* @param key 键* @param value 值*/public void put(String key, String value) {//如果key存在,则将key移动到最前端if (map.containsKey(key)) {list.remove(key);list.add(0, key);map.put(key, value);} else {//如果key不存在,则添加key-valueif (list.size() >= capacity) {//如果容量已满,则删除最后一个keyString lastKey = list.get(list.size() - 1);list.remove(lastKey);map.remove(lastKey);}list.add(0, key);map.put(key, value);}}public void showList(){System.out.println(list.toString());}public static void main(String[] args) {LRUCache cache = new LRUCache(5);cache.put("A", "数据结构篇:深度剖析LSM及与B+树优劣势分析");cache.put("B", "数据结构篇:深度剖析跳跃表及与B+树优劣分析");cache.put("C", "算法之美:堆排序原理剖析及应用案例分解实现");cache.put("D", "海量数据项目大课是营销短链平台项目");cache.put("E", "算法之美:二叉堆原理剖析及堆应用案例讲解及实现");cache.showList();Object cacheObj2 = cache.get("C");System.out.println("cacheObj2=" + cacheObj2);//C被访问,被放置头部cache.showList();cache.put("F", "算法之美:B+树原理、应用及Mysql索引底层原理剖析");//新增了F,超过大小,A由于在尾部,被删除,F被放置头部cache.showList();//G节点不存在,所以不影响顺序Object cacheObj1 = cache.get("G");System.out.println("cacheObj1=" + cacheObj1);cache.showList();}
}

LFU最近最少使用算法

        Least Frequently Used 最近最少使用,增加次数作为参考,淘汰一定时期内被访问次数最少的数据。设计者认为如果数据过去被访问多次,那么将来被访问的频率也更高,比LRU多了一个频次统计,需要时间和次数两个维度进行判断是否淘汰。新加入数据插入到队列尾部,需要将引用计数初始值为 1,当队列中的数据被访问后,对应的元素引用计数 +1,队列按【次数】重新排序,如果相同次数则按照时间排序,当需要淘汰数据时,将排序的队列末尾的数据删除,即访问次数最少。

public class LFUCache {//定义缓存容量private  int capacity ;//存储key valueprivate Map<String,String> cache ;//存储key的使用频次private Map<String, CacheObj> count;public LFUCache(int capacity){this.capacity = capacity;cache =  new HashMap<>();count =  new HashMap<>();}//存储public void put(String key, String value) {}//读取public String get(String key) {}//删除元素private void removeElement() {}//更新相关统计频次和时间private void addCount(String key) {}public void showInfo(){System.out.println(cache.toString());System.out.println(count.toString());}class CacheObj implements Comparable<CacheObj>{private String key;private int count;private long lastTime;public String getKey() {return key;}public void setKey(String key) {this.key = key;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public long getLastTime() {return lastTime;}public void setLastTime(long lastTime) {this.lastTime = lastTime;}public CacheObj(String key, int count, long lastTime) {this.key = key;this.count = count;this.lastTime = lastTime;}//用于比较大小,如果使用次数一样,则比较时间大小@Overridepublic int compareTo(CacheObj o) {int value = Integer.compare(this.count, o.count);return value == 0 ? Long.compare(this.lastTime, o.lastTime) : value;}@Overridepublic String toString() {return "CacheObj{" +"key=" + key +", count=" + count +", lastTime=" + lastTime +'}';}}
}
public class LFUCache {//定义缓存容量private  int capacity ;//存储key valueprivate Map<String,String> cache ;//存储key的使用频次private Map<String, CacheObj> count;public LFUCache(int capacity){this.capacity = capacity;cache =  new HashMap<>();count =  new HashMap<>();}//存储public void put(String key, String value) {String cacheValue = cache.get(key);if (cacheValue == null) {//新元素插入,需要判断是否超过缓存容量大小if (cache.size() == capacity) {removeElement();}count.put(key, new CacheObj(key, 1, System.currentTimeMillis()));} else {addCount(key);}cache.put(key, value);}//读取public String get(String key) {String value = cache.get(key);if (value != null) {addCount(key);return value;}return null;}//删除元素private void removeElement() {CacheObj cacheObj  = Collections.min(count.values());cache.remove(cacheObj.getKey());count.remove(cacheObj.getKey());}//更新相关统计频次和时间private void addCount(String key) {CacheObj cacheObj = count.get(key);cacheObj.setCount(cacheObj.getCount()+1);cacheObj.setLastTime(System.currentTimeMillis());}public void showInfo(){System.out.println(cache.toString());System.out.println(count.toString());}class CacheObj implements Comparable<CacheObj>{private String key;private int count;private long lastTime;public CacheObj(String key, int count, long lastTime) {this.key = key;this.count = count;this.lastTime = lastTime;}//用于比较大小,如果使用次数一样,则比较时间大小@Overridepublic int compareTo(CacheObj o) {int value = Integer.compare(this.count, o.count);return value == 0 ? Long.compare(this.lastTime, o.lastTime) : value;}@Overridepublic String toString() {return "CacheObj{" +"key=" + key +", count=" + count +", lastTime=" + lastTime +'}';}}
}
public static void main(String[] args) {LFUCache cache = new LFUCache(2);cache.put("A", "数据结构篇:深度剖析LSM及与B+树优劣势分析");cache.put("A", "数据结构篇:深度剖析跳跃表及与B+树优劣分析");cache.showInfo();System.out.println("---------");String cacheValue = cache.get("A");System.out.println(cacheValue);cache.showInfo();System.out.println("---------");cache.put("B", "算法之美:堆排序原理剖析及应用案例分解实现");cache.put("B", "算法之美:二叉堆原理剖析及堆应用案例讲解及实现");cache.showInfo();System.out.println("---------");//插入新元素,由于A的count是3,B的count是2,所以淘汰了Bcache.put("C","算法之美:B+树原理、应用及Mysql索引底层原理剖析");cache.showInfo();
}

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

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

相关文章

《乡土中国》中国基层传统社会里的一种体系,支配着社会生活的各方面 - 三余书屋 3ysw.net

乡土中国 大家好&#xff0c;今天我们要解读的是费孝通先生的经典著作《乡土中国》。这本书的中文版大约有10万字&#xff0c;我将用30分钟左右的时间为你解读书中的精髓。为什么说中国的根基在于乡土社会&#xff1f;我们应该从哪些方面来理解乡土社会的特征及其重要性&#…

穿越雷区(Java--BFS解法)

穿越雷区&#xff08;Java–BFS解法&#xff09; 题目链接&#xff1a;http://oj.ecustacm.cn/problem.php?id1266 解题代码&#xff08;内含注释思路&#xff09; import java.util.*;public class Main {static int[][] dir {{0,1},{0,-1},{1,0},{-1,0}};static String[]…

Oracle备份和还原的几种方式

1、使用数据泵方式 exp demo/demoorcl buffer1024 filed&#xff1a;\back.dmp fully demo&#xff1a;用户名、密码 buffer: 缓存大小 file: 具体的备份文件地址 full: 是否导出全部文件 ignore: 忽略错误&#xff0c;如果表已经存在&#xff0c;则也是覆盖 exp demo/de…

JAVA 100道题(26)

26.编写一个JAVA程序&#xff0c;将文本文件中的内容读取到内存中并打印出来 以下是一个简单的Java程序&#xff0c;用于读取文本文件的内容并将其打印到控制台上&#xff1a; java复制代码 import java.io.BufferedReader; import java.io.FileReader; import java.io.IOExce…

MyBatis与Hibernate的优缺点对比

MyBatis和Hibernate都是Java中常用的持久化框架&#xff0c;它们各自有着优点和缺点。让我们来对比一下它们的优缺点。 MyBatis 优点&#xff1a; SQL控制: MyBatis允许开发人员直接编写SQL语句&#xff0c;提供了更直观的数据库访问控制。灵活性: 开发人员可以更精细地控制…

LeetCode 856. 括号的分数

解题思路 栈模拟。 相关代码 class Solution {public int scoreOfParentheses(String s) {//stack中的值是左括号的的右边所有合法配对括号的值Stack<Integer> stack new Stack<>();stack.push(0);for(int i0;i<s.length();i)if(s.charAt(i) () stack.push…

nvm 安装多个版本的Node npm

先安装nvm 管理工具 git安装地址 找到安装包 下载然后安装 https://github.com/coreybutler/nvm-windows/releases/tag/1.1.11nvm常用命令 命令说明nvm version查看nvm版本nvm ls查看所有已经安装的Nodejs版本nvm list installed查看所有已经安装的Nodejs版本nvm ls availab…

第十一章 U-boot 顶层 Makefile 详解 (模块编译)

11.2.7 模块编译 在 uboot 中允许单独编译某个模块,使用命令" make Mdir"&#xff0c;旧语法"makeSUBDIRSdir"也是支持的。 200 # Use make Mdir to specify directory of external module to build 201 # Old syntax make ... SUBDIRS$PWD is still supp…

网站排名不升反降?揭秘SEO中常见的降权触发点!

在SEO(搜索引擎优化)中&#xff0c;网站的权重是影响其在搜索引擎中排名的重要因素。然而&#xff0c;有许多原因可能导致网站被降权&#xff0c;以下是一些常见的原因&#xff1a; 1. 网站内容过于雷同或不相关性&#xff1a;如果网站的内容大量复制自其他网站&#xff0c;或…

笔试:4.6美团笔试(硬件开发方向)

二十道选择两道算法题。 选择就不说了&#xff0c;硬件方面目前了解较少。 两道算法题都过了&#xff0c;第一题很简单没有什么好讲的。 第二题看着题目以为会很复杂&#xff0c;没想到一遍过。 小美有一个由 n 个互不相等的正整数构成的数组 a&#xff0c;但她一不小心把 a…

Three 之 three.js (webgl)GLSL-Card 中文手册相关知识

Three 之 three.js &#xff08;webgl&#xff09;GLSL-Card 中文手册相关知识 目录 Three 之 three.js &#xff08;webgl&#xff09;GLSL-Card 中文手册相关知识 一、简单介绍 二、GLSL 中文手册 1、基本类型 2、基本结构和数组 3、向量的分量访问 4、运算符 5、基础…

<c++基础(5)>整数溢出

整数溢出 在工程中遇到问题&#xff0c;两个int类型加减结果赋值给double类型时提示溢出风险&#xff1a; //sum和sumb都是int类型&#xff0c; double a double(sum - sumB);这里发生了整数溢出&#xff0c;整数溢出是指当计算结果超出了整数类型所能表示的范围时发生的情况…

南京观海微电子---Vitis HLS设计流程(实例演示)——Vitis HLS教程

1. 前言 课时2我们介绍了Vitis HLS的设计流程&#xff0c;如下图所示&#xff1a; 算法或软件的设计和仿真都基于C/C&#xff0c;通过HLS平台导出打包好的IP RTL代码&#xff0c;最后将该打包的IP加入到主工程使用。 本课时&#xff0c;我们通过一个具体的实例&#xff0c;演示…

Dapr(三) Dapr核心组件的使用一

结合前两期 Dapr(一) 基于云原生了解Dapr(Dapr(一) 基于云原生了解Dapr-CSDN博客) Dapr(二) 分布式应用运行时搭建及服务调用(Dapr(二) 分布式应用运行时搭建及服务调用-CSDN博客) 下篇推出dapr服务注册与发现&#xff0c;dapr组件绑定&#xff0c;dapr Actor功能。 目录 1.…

中颖51芯片学习2. IO端口操作

一、SH79F9476 I/O端口介绍 1. 特性 SH79F9476提供了30/26位可编程双向 I/O 端口&#xff1b;端口数据在寄存器Px中&#xff1b;端口控制寄存器PxCRy是控制端口作为输入还是输出&#xff1b;端口作为输入时&#xff0c;每个I/O端口均带有PxPCRy控制的内部上拉电阻。有些I/O引…

超详细!211页网络协议与管理,看完终于明白了(建议收藏)

与其说计算机改变了世界&#xff0c;不如说是计算机网络改变了世界。作为计算机网络通信实体之间的语言&#xff0c;网络通信协议对计算机正常通信起着极大的作用。 那么到底什么是网络协议与管理呢&#xff1f;今天给大家分享一份211页网络协议与管理文档&#xff0c;包含概念…

碧桂园服务净利降两成,关联交易收入仅占2.9%,发力增值服务充电桩日进超10万

自2018年分拆上市以来&#xff0c;碧桂园服务经历过非常高速的发展&#xff0c;曾是物管市场的“并购王”&#xff0c;但从2023年开始&#xff0c;希望从外延式的增长向内生式增长转型&#xff0c;将往期的经验与教训&#xff0c;通过投后管理沉淀下来&#xff0c;向高质量发展…

nginx多https证书配置精简

其实有很多方式&#xff0c;网上看到一个这个方法&#xff0c;给大家介绍一下。 首先&#xff0c;开启支持-TLS SNI support Nginx开启单IP多SSL证书支持-TLS SNI support Nginx支持单IP多域名SSL证书需要OpenSSL支持&#xff0c;首先需要编译安装一个高版本的openssl。 检查…

04 Python进阶:MySQL-PyMySQL

什么是 PyMySQL&#xff1f; PyMySQL 是一个用于 Python 的纯 Python MySQL 客户端库&#xff0c;提供了与 MySQL 数据库进行交互的功能。PyMySQL 允许 Python 开发人员连接到 MySQL 数据库服务器&#xff0c;并执行诸如查询、插入、更新和删除等数据库操作。 以下是 PyMySQL …

自动驾驶领域中的感知,决策,控制

目录 一、自动驾驶领域感知决策控制概论 二、自动驾驶感知 三、自动驾驶决策 四、自动驾驶控制 一、自动驾驶领域感知决策控制概论 1.感知&#xff08;Perception&#xff09;&#xff1a;感知是指系统通过各种传感器来感知周围环境的能力&#xff0c;包括识别和理解道路、…