LRU算法及实现

1.LRU算法是什么?

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法
选择最近最久未使用的数据予以淘汰。
除此之外,在redis缓存中也是用到了这种算法。redis有读写两个操作,然后缓存是有空间限制的,大小会有一定上线的,

2.算法来源

来自https://leetcode-cn.com/problems/lru-cache/

运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。
实现 LRUCache 类:

LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?

示例:

输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
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

3.设计思想

进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作?
这里要求一次命中,写要写成功,读也要读成功。
思考java中什么样的数据结构能一次找到。
1.所谓缓存,必须要有读+写操作,按照命中率的思路考虑,写操作时间复杂度都需要为O(1)
2.特性要求
2.1.必须要有顺序之分,一区分最近使用的和很久没有使用的数据排序
2.2.写和读操作一次搞定
2.3.**如果容量(坑位)满了要删除最不常用的数据,每次新访问还要把新的数据插入到队头(**按照业务你自己设定左右那一边是队头)
查找快、插入快、删除快,且还需要先后排序------->什么样的数据结构可以满足这个问题?
你是否可以在O(1)时间复杂度内完成这个操作?
如果一次就可以找到,你觉得什么数据结构最合适??
哈希存储结构
LRU的算法核心是哈希+链表
本质就是HashMap+DoubleLinkedList,时间复杂度O(1),哈希表+双向链表的结合体
哈希能够实现O(1)时间内的查找,双向链表能够保证增删比较快。即查找用哈希,增删用链表。

4.编码手写如何实现LRU

巧用LinkedHashMap完成lru算法

查看API,可以看到继承自HashMap

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>

这种数据结构非常适合于构造LRU算法
eldest是最近最少使用的entry插入到map中。

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
    
    
    return false;
}

以下是代码实现

public class LRUCacheDemo<K,V> extends LinkedHashMap<K,V>{
    
    
	private int capacity;
	public LRUCacheDemo(int capacity){
    
    
		//参数1,坑位,传过来的值,参数2,加载因子,参数3,访问顺序
		super(capacity,0.75F,true);
		this.capacity=capacity;
	}
	//怎么弹出去一个坑位
	@Override
	protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
    
    
		return super.size()>capacity;
	}
	public static void main(String[] args) {
    
    
		//坑位是3个
		LRUCacheDemo lruCacheDemo=new LRUCacheDemo<>(3);
		lruCacheDemo.put(1,"a");
		lruCacheDemo.put(2,"b");
		lruCacheDemo.put(3,"c");
		System.out.println(lruCacheDemo.keySet());
		lruCacheDemo.put(4,"d");
		System.out.println(lruCacheDemo.keySet());
		lruCacheDemo.put(3,"c");
		System.out.println(lruCacheDemo.keySet());
		lruCacheDemo.put(3,"c");
		System.out.println(lruCacheDemo.keySet());
		lruCacheDemo.put(3,"c");
		System.out.println(lruCacheDemo.keySet());
		lruCacheDemo.put(3,"c");
		System.out.println(lruCacheDemo.keySet());
		lruCacheDemo.put(5,"x");
		System.out.println(lruCacheDemo.keySet());
	}
}

最后运行结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39736597/article/details/113791512
今日推荐