146.LRU缓存机制
一、JS有关知识点
1、map数据结构的使用
// 声明一个Map数据结构
var map = new Map();
// 得到map中的第一个元素
map.key() ; // 返回的是一个迭代的对象
map.key().next().value; // 开始得到第一个元素
map.key().next().value; // 开始得到第二个元素
2、初始化的声明
var LRUCache = function(capacity) {
// 初始化一个容量和数据结构Map
this.capacity = capacity;
// 注意这里不是用的var map = new Map();
this.map = new Map();
};
二、使用Map数据结构
Map的set操作是默认在末尾插入的。所以进行更新的时候,可以先delete,然后set.
var LRUCache = function(capacity) {
// 初始化一个容量和数据结构Map
this.capacity = capacity;
this.map = new Map();
};
// 定义LRUCache对象的get()方法
LRUCache.prototype.get = function(key) {
// 方便书写,即map就是指代的LRUCache对象的map
let map = this.map;
// 如果存在,返回key的value,并且更新位置
if (map.has(key)){
let value = map.get(key);
// 更新位置,先delete,然后set加入。set每次加入默认在末尾
map.delete(key);
map.set(key,value);
return value;
}else{
return -1;
}
};
LRUCache.prototype.put = function(key, value) {
let map = this.map;
// 如果存在,先delete再set, 元素便会置为最新使用。
// 如果不存在且容器超过限制,那么先删除第一个最远的元素,然后再set
if (map.has(key)){
map.delete(key);
}else if(map.size >= this.capacity){
map.delete(map.keys().next().value);
}
// 无论是否存在都要添加进去
map.set(key,value);
};
三、双链表
1、整个LRU的功能工作机制:双链表 + 哈希表
整个流程:
2、需要进行的操作
(1)当使用put()方法放入元素的时候, 向末尾添加元素
(2)当出现更新操作,或者是元素被访问的时候,将某一元素移到尾部
(3)当容量满的时候,在头部删除不被经常访问的元素
3、数据结构![在这里插入图片描述](https://img-blog.csdnimg.cn/daff0a0872394c69987b07525ee7f138.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5piv6aao5ZGA77yB,size_20,color_FFFFFF,t_70,g_se,x_16)
三、代码实现
# 定义一个双链表的节点
class LinkNode:
def __init__(self,key=None,value=None):
self.key = key
self.value = value
self.next = None
self.pre = None
class LRUCache:
# 初始化LRU缓存
def __init__(self, capacity: int):
self.capacity = capacity
# 定义一个hashmap的字典
self.hashmap = {}
# 定义头节点和尾节点
self.head = LinkNode()
self.tail = LinkNode()
# 构成双链表
self.head.next = self.tail
self.tail.pre = self.head
# 将节点放到末尾
def move_to_end(self,node):
node.next = self.tail
node.pre = self.tail.pre
# 这个要注意连接的先后顺序
self.tail.pre.next = node
self.tail.pre = node
# 定义一个将某个节点从中间拆开移到末尾的方法
def from_middle_move_to_end(self,key):
# 将哈希表key指向的节点拎出来
node = self.hashmap[key]
node.pre.next = node.next
node.next.pre = node.pre
# 放到末尾
self.move_to_end(node)
# 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
def get(self, key: int) -> int:
if key in self.hashmap:
# get就是进行访问,所以要将其移到尾部
self.from_middle_move_to_end(key)
return self.hashmap[key].value
return -1
# 如果关键字key已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组key-value。如果插入操作导致关键字数量超过capacity,则应该逐出最久未使用的关键字。
def put(self, key: int, value: int) -> None:
# 如果存在
if key in self.hashmap:
# 变更value的值,并将其插入到尾部(相当于被访问)
self.hashmap[key].value = value
self.from_middle_move_to_end(key)
else:
# 不存在的时候,要插入元素。但是要考虑容量问题
if len(self.hashmap) == self.capacity:
# 删除hanshmap里面存储头节点之后的节点的值
self.hashmap.pop(self.head.next.key)
# 删除节点只需要断开其中两个指针即可。
self.head.next = self.head.next.next
self.head.next.pre = self.head
# 新节点插入尾部
new = LinkNode(key,value)
# 添加到hashmap中
self.hashmap[key] = new
# 放到末尾
self.move_to_end(new)
# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)