数据结构:自己实现一个LRU的缓存(初始化传入缓存最大容量)

最近爱上了刷力扣,越刷越上瘾!然后今天有道题是让自己实现一个【LRUCache】,也就是LRU缓存。LRU缓存呢,就是当容量不够的时候就要淘汰掉最近最少使用的缓存值,也就是【Least Recently Used】,这也就是LRU缓存名字的由来。至于为什么容量不够的时候要优先淘汰掉最近最少使用的缓存值呢?这个就涉及到计算机科学里面大名鼎鼎的【局部性原理】了!

我在力扣上面提交的题也不少了,这道题还是比较有意思的(这道题的力扣网址),我也是直接借用了JDK的LinkedHashMap来实现的,这里直接上代码:

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Leetcode Website: https://leetcode-cn.com/problems/lru-cache-lcci/
 * @author : LiYang
 * @datetime : 2021/7/7 22:35
 */
public class LRUCache {

    /**
     * 存缓存值的Map
     */
    private Map<Integer, Integer> cache;
    /**
     * 缓存容量
     */
    private int capacity;

    /**
     * 构造方法,传入容量
     * @param capacity 缓存容量
     */
    public LRUCache(int capacity) {
        // 初始化缓存容量
        this.capacity = capacity;

        // 将村缓存的Map初始化为LinkedHashMap
        cache = new LinkedHashMap<>(capacity);
    }

    /**
     * 获取缓存值
     * @param key 缓存键
     * @return 值
     */
    public int get(int key) {
        // 先从缓存中删除,并拿到值
        Integer value = cache.remove(key);

        // 如果有值
        if (value != null) {
            // 重新添加到末尾
            cache.put(key, value);
            // 返回该缓存值
            return value;

        } else {
            // 没有值,返回-1
            return -1;
        }
    }

    /**
     * 添加缓存值
     * @param key 键
     * @param value 值
     */
    public void put(int key, int value) {
        // 先删除原值
        cache.remove(key);
        // 添加新值到末尾
        cache.put(key, value);

        // 如果超了容量,则删除至最大容量
        while (cache.size() > capacity) {
            cache.remove(cache.keySet().iterator().next());
        }
    }

}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 我可以给你一些简单的步骤来实现LRU缓存:1. 使用一个哈希表来存储键和值的映射。2. 使用一个双端链表来存储键,以按照访问顺序排列。3. 如果键存在于缓存中,将其移动到双端链表的头部,表示这个键最近被访问了。4. 如果缓存容量已满,则将尾部的键删除,以便空出空间。 ### 回答2: 要用Go语言实现一个LRU(Least Recently Used)缓存,可以使用该语言提供的一些数据结构和函数来简化操作。 首先,我们需要创建一个结构体来表示缓存项。每个缓存项包含键和值两个字段。 ```go type CacheItem struct { key string value interface{} } ``` 接下来,我们创建一个结构体来表示LRU缓存,其中包含一个哈希表和一个双向链表。 ```go type LRUCache struct { capacity int cacheMap map[string]*list.Element cacheList *list.List } ``` 在LRUCache结构体中,哈希表cacheMap用于存储键和对应链表元素的映射关系,以便在O(1)时间复杂度内快速访问缓存项。双向链表cacheList用于存储实际的缓存项,其中最近被访问的项放在链表头部,最久未被访问的项放在链表尾部。 接下来,我们来实现LRUCache的一些方法: 1. 初始化缓存。 ```go func NewLRUCache(capacity int) *LRUCache { return &LRUCache{ capacity: capacity, cacheMap: make(map[string]*list.Element), cacheList: list.New(), } } ``` 2. 获取缓存项。 ```go func (c *LRUCache) Get(key string) (interface{}, bool) { if element, ok := c.cacheMap[key]; ok { c.cacheList.MoveToFront(element) return element.Value.(*CacheItem).value, true } return nil, false } ``` 3. 插入缓存项。 ```go func (c *LRUCache) Put(key string, value interface{}) { if element, ok := c.cacheMap[key]; ok { c.cacheList.MoveToFront(element) element.Value.(*CacheItem).value = value } else { if c.cacheList.Len() >= c.capacity { tail := c.cacheList.Back() delete(c.cacheMap, tail.Value.(*CacheItem).key) c.cacheList.Remove(tail) } element := c.cacheList.PushFront(&CacheItem{ key: key, value: value, }) c.cacheMap[key] = element } } ``` 在插入缓存项时,首先检查是否已存在该键。如果存在,则将缓存项移到链表头部,同时更新对应的值。如果不存在,则检查缓存容量是否已满,如果已满,则删除链表尾部的缓存项,并从哈希表中删除对应的键;然后,插入新的缓存项到链表头部,并在哈希表中添加对应的键和链表元素的映射关系。 这样,就可以用Go语言实现一个LRU缓存了。 ### 回答3: 使用Go语言实现一个LRU(Least Recently Used)缓存可以通过使用哈希表和双向链表来实现。 首先,我们需要定义一个缓存结构体,其中包含一个哈希表和两个链表指针,分别用于存储缓存的键值对和维护访问顺序。 ```go type LRUCache struct { capacity int cache map[int]*Node head *Node tail *Node } type Node struct { key int value int prev *Node next *Node } ``` 在初始化LRU缓存时,我们需要指定缓存容量并创建一个空的哈希表。 ```go func NewLRUCache(capacity int) *LRUCache { return &LRUCache{ capacity: capacity, cache: make(map[int]*Node), head: nil, tail: nil, } } ``` 接下来,我们需要实现四个核心的功能方法:获取缓存值、添加新的缓存值、移动已存在的缓存值到链表头部以及移除最久未使用的缓存。 首先,我们实现Get方法用于获取缓存值。当需要获取某个缓存值时,如果该值存在于哈希表中,我们需要将其移动到链表头部表示最近被访问过,并返回其值。否则,返回-1表示该缓存值不存在。 ```go func (l *LRUCache) Get(key int) int { if node, ok := l.cache[key]; ok { l.moveToHead(node) return node.value } return -1 } ``` 其次,我们实现Put方法用于添加新的缓存值。当需要添加新的缓存值时,首先判断该值是否已存在于哈希表中,如果存在,则更新该值的节点,并将节点移动到链表头部。如果不存在,检查缓存是否已满,如果已满,则需要移除链表尾部的节点,并从哈希表中删除相应的键。最后,创建一个新节点,并将其添加到链表头部和哈希表中。 ```go func (l *LRUCache) Put(key int, value int) { if node, ok := l.cache[key]; ok { node.value = value l.moveToHead(node) return } if len(l.cache) == l.capacity { delete(l.cache, l.tail.key) l.removeTail() } newNode := &Node{ key: key, value: value, prev: nil, next: nil, } l.addToHead(newNode) l.cache[key] = newNode } ``` 最后,我们需要实现两个辅助方法moveToHead和removeTail,分别用于将某个节点移动到链表头部和移除链表尾部的节点。 ```go func (l *LRUCache) moveToHead(node *Node) { if node == l.head { return } l.removeNode(node) l.addToHead(node) } func (l *LRUCache) removeTail() { if l.tail == nil { return } if l.tail == l.head { l.head = nil l.tail = nil return } l.tail = l.tail.prev l.tail.next = nil } func (l *LRUCache) removeNode(node *Node) { if node.prev != nil { node.prev.next = node.next } else { l.head = node.next } if node.next != nil { node.next.prev = node.prev } else { l.tail = node.prev } } func (l *LRUCache) addToHead(node *Node) { node.prev = nil node.next = l.head if l.head != nil { l.head.prev = node } l.head = node if l.tail == nil { l.tail = node } } ``` 至此,我们通过使用哈希表和双向链表实现一个LRU缓存。这样,我们可以在O(1)的时间复杂度下对缓存进行读和写操作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值