油边机 东莞网站建设四川德行天下建设工程有限公司网站
web/
2025/10/6 0:33:07/
文章来源:
油边机 东莞网站建设,四川德行天下建设工程有限公司网站,企业网站模板网页模板,中国建设安全协会网站目录
1.什么是LRU算法
2.LRU算法原题描述
3.LRU算法设计
4.LRU算法细节分析
5.代码实现 1.什么是LRU算法
就是一种缓存淘汰策略。
计算机的缓存容量有限#xff0c;如果缓存满了就要删除一些内容#xff0c;给新内容腾位置。但问题是#xff0c;删除哪些内容呢#…目录
1.什么是LRU算法
2.LRU算法原题描述
3.LRU算法设计
4.LRU算法细节分析
5.代码实现 1.什么是LRU算法
就是一种缓存淘汰策略。
计算机的缓存容量有限如果缓存满了就要删除一些内容给新内容腾位置。但问题是删除哪些内容呢我们肯定希望删掉哪些没什么用的缓存而把有用的数据继续留在缓存里方便之后继续使用。那么什么样的数据我们判定为「有用的」的数据呢
LRU 缓存淘汰算法就是一种常用策略。LRU 的全称是 Least Recently Used也就是说我们认为最近使用过的数据应该是是「有用的」很久都没用过的数据应该是无用的内存满了就优先删那些很久没用过的数据。
2.LRU算法原题描述
举一个例子
假设我的手机只允许我同时开 3 个应用程序现在已经满了。那么如果我新开了一个应用「时钟」就必须关闭一个应用为「时钟」腾出一个位置关那个呢
按照 LRU 的策略就关最底下的因为那是最久未使用的然后把新开的应用放到最上面
现在你应该理解 LRULeast Recently Used策略了。
我们先从一道LRU设计算法题开始
运用你所掌握的数据结构设计和实现一个 LRU (最近最少使用) 缓存机制。支持以下操作
获取数据 get 和 写入数据 put 。获取数据 get(key) - 如果关键字 (key) 存在于缓存中则获取关键字的值总是正数否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在则变更其数据值如果关键字不存在则插入该组「关键字/值」。当缓存容量达到上限时它应该在写入新数据之前删除最久未使用的数据值从而为新的数据值留出空间。
O(1) 时间复杂度内完成这两种操作
3.LRU算法设计
分析上面的操作过程要让 put 和 get 方法的时间复杂度为 O(1)我们可以总结出 cache 这个数据结构必要的条件查找快插入快删除快有顺序之分。
因为必须有顺序之分以区分最近使用的和久未使用的数据而且我们要查找键是否已存在如果容量满了要删除最后一个数据每次访问还要把数据插入到队头。
那么什么数据结构同时符合上述条件呢哈希表查找快但是数据无固定顺序链表有顺序之分插入删除快但是查找慢。所以结合一下形成一种新的数据结构哈希链表。
LRU 缓存算法的核心数据结构就是哈希链表双向链表和哈希表的结合体。这个数据结构长这样 在双向链表中特意增加两个节点不用来存储任何数据。使用节点增加/删除节点的时候就可以不用考虑边界节点不存在情况简化编程难度降低代码复杂度。 思想听起来很简单就是借助哈希表赋予了链表快速查找的特性嘛可以快速查找某个 key 是否存在缓存链表中同时可以快速删除、添加节点。回想刚才的例子这种数据结构是不是完美解决了 LRU 缓存的需求
也许大家会问为什么要是双向链表单链表行不行另外既然哈希表中已经存了 key为什么链表中还要存键值对呢只存值不就行了
这样设计的原因必须等我们亲自实现 LRU 算法之后才能理解所以我们开始一步步实现代码吧
4.LRU算法细节分析
新插入的元素或者最新查询的元素要放到链表的头部对于长时间未访问的元素要放到链表尾部所以每次插入或者查询都需要维护链表中元素的顺序。
使用哈希表的原因是查询时间复杂度为O(1)使用双向链表的原因是对于删除和插入操作时间复杂度为O(1)。
其中哈希表中存储的 key 为 Kvalue 为 NodeK,V 的引用双向链表存储的元素为NodeK,V的引用.
对于put操作
①首先判断缓存中 元素 K 是否存在如果存在则把链表中的元素NodeK, V删除map中的数据K, NodeK, V 不用删除再在链表头部插入元素并更新map直接返回即可
②缓存不存在并且缓存没有满的话直接把元素插入链表的表头缓存满了的话移除表尾元素最旧未访问元素,将元素K插入表头增加map中的K, NodeK, V, 更新map。
对于get操作
首先要判断 缓存中(map)是否存在如果存在则把该节点删除并在链表头部插入该元素并更新map 返回当前元素即可如果map不存在 则直接返回-1
5.代码实现
public class LRUCache {Entry head, tail;int capacity;int size;MapInteger, Entry cache;public LRUCache(int capacity) {this.capacity capacity;// 初始化链表initLinkedList();size 0;cache new HashMap(capacity 2);}/*** 如果节点不存在返回 -1.如果存在将节点移动到头结点并返回节点的数据。** param key* return*/public int get(int key) {Entry node cache.get(key);if (node null) {return -1;}// 存在移动节点moveToHead(node);return node.value;}/*** 将节点加入到头结点如果容量已满将会删除尾结点** param key* param value*/public void put(int key, int value) {Entry node cache.get(key);if (node ! null) {node.value value;moveToHead(node);return;}// 不存在。先加进去再移除尾结点// 此时容量已满 删除尾结点if (size capacity) {Entry lastNode tail.pre;deleteNode(lastNode);cache.remove(lastNode.key);size--;}// 加入头结点Entry newNode new Entry();newNode.key key;newNode.value value;addNode(newNode);cache.put(key, newNode);size ;}private void moveToHead(Entry node) {// 首先删除原来节点的关系deleteNode(node);addNode(node);}private void addNode(Entry node) {head.next.pre node;node.next head.next;node.pre head;head.next node;}private void deleteNode(Entry node) {node.pre.next node.next;node.next.pre node.pre;}public static class Entry {public Entry pre;public Entry next;public int key;public int value;public Entry(int key, int value) {this.key key;this.value value;}public Entry() {}}private void initLinkedList() {head new Entry();tail new Entry();head.next tail;tail.pre head;}public static void main(String[] args) {LRUCache cache new LRUCache(2);cache.put(1, 1);cache.put(2, 2);System.out.println(cache.get(1));cache.put(3, 3);System.out.println(cache.get(2));}
}
如果大家完全理解了LRU算法那么练习结果这个相信大家一眼就可以看出
分析
1.首先我们给出的容量是2先push 1 后push 2那么现在数据存储顺序应该是21
2.我们接下来对于1这个值进行了查询因为1这个值存在所以1这个值被引用了一次1这个值放到最上边返回1现在的顺序是12
3.现在push数据3因为容量只有2所以淘汰掉末尾数据2现在顺序变为31
4.最后查询数据2因为没有数据2所以返回-1顺序不变
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/87640.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!