LRU算法及实现

76 篇文章 1 订阅
本文详细介绍了LRU(最近最少使用)算法,它常用于页面置换和缓存策略。通过使用HashMap和双向链表的组合,可以在O(1)的时间复杂度内实现读写操作。具体实现中,通过继承LinkedHashMap并重写removeEldestEntry方法来达到LRU的效果。当缓存满时,最不常使用的数据会被淘汰。示例代码展示了如何创建一个LRUCache,并进行了操作演示。
摘要由CSDN通过智能技术生成

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());
	}
}

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

LRU(Least Recently Used)算法是一种常见的缓存淘汰策略,用于在缓存容量不足时,淘汰最近最少使用的缓存块。下面是LRU算法的C语言实现: ``` #include <stdio.h> #include <stdlib.h> typedef struct Node { int key; int value; struct Node *next; struct Node *prev; } Node; typedef struct LRU { int size; int capacity; Node *head; Node *tail; } LRU; LRU* newLRU(int capacity) { LRU *lru = (LRU*)malloc(sizeof(LRU)); lru->size = 0; lru->capacity = capacity; lru->head = NULL; lru->tail = NULL; return lru; } void deleteNode(LRU *lru, Node *node) { if (node == lru->head) { lru->head = node->next; } else { node->prev->next = node->next; } if (node == lru->tail) { lru->tail = node->prev; } else { node->next->prev = node->prev; } free(node); } void moveToHead(LRU *lru, Node *node) { if (node == lru->head) { return; } if (node == lru->tail) { lru->tail = node->prev; lru->tail->next = NULL; } else { node->prev->next = node->next; node->next->prev = node->prev; } node->next = lru->head; node->prev = NULL; lru->head->prev = node; lru->head = node; } void set(LRU *lru, int key, int value) { Node *node = lru->head; while (node != NULL) { if (node->key == key) { node->value = value; moveToHead(lru, node); return; } node = node->next; } if (lru->size >= lru->capacity) { deleteNode(lru, lru->tail); lru->size--; } Node *newNode = (Node*)malloc(sizeof(Node)); newNode->key = key; newNode->value = value; newNode->next = NULL; newNode->prev = NULL; if (lru->head == NULL) { lru->head = newNode; lru->tail = newNode; } else { newNode->next = lru->head; lru->head->prev = newNode; lru->head = newNode; } lru->size++; } int get(LRU *lru, int key) { Node *node = lru->head; while (node != NULL) { if (node->key == key) { moveToHead(lru, node); return node->value; } node = node->next; } return -1; // 缓存未命中 } ``` LRU算法的主要思想是将最近访问的缓存块移动到链表头部,当缓存容量不足时,淘汰链表尾部的缓存块。实现中用双向链表和哈希表来存储缓存块,双向链表用于记录最近访问顺序,哈希表用于快速查找缓存块。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值