146.LRU缓存机制 JavaScript实现

146.LRU缓存机制

LUR缓存机制

一、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、数据结构在这里插入图片描述

三、代码实现

# 定义一个双链表的节点
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)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值