什么是LRU

LRU(Least Recently Used)是一种缓存淘汰算法。它是根据缓存中数据项的使用历史来决定哪些数据应该被淘汰出缓存。LRU算法的基本原则是:当缓存已满时,最近最少使用的数据项将被淘汰,以便为新的数据项腾出空间。

LRU算法维护了一个按照访问时间排序的数据项列表。每当一个数据项被访问时,它就会被提升到列表的顶部,表示它是最近使用过的。当需要淘汰数据时,列表底部的数据项就会被移除,因为它们是最近最少使用的。

LRU算法的优势在于它可以有效地利用缓存空间,因为它倾向于保留最近被频繁使用的数据项。这对于那些具有局部性的访问模式非常有用,因为这些访问模式通常会导致某些数据被反复使用,而其他数据则很少被使用。

总结来说,LRU算法是一种基于最近使用历史的缓存淘汰策略,它通过淘汰最近最少使用的数据项来为新的数据项腾出空间。


golang实现一个LRU

下面是使用Golang实现一个简单的LRU(Least Recently Used)缓存的示例代码:

package main

import (
	"container/list"
	"fmt"
)

type LRUCache struct {
	capacity int
	cache    map[int]*list.Element
	lruList  *list.List
}

type entry struct {
	key   int
	value int
}

func NewLRUCache(capacity int) *LRUCache {
	return &LRUCache{
		capacity: capacity,
		cache:    make(map[int]*list.Element),
		lruList:  list.New(),
	}
}

func (lru *LRUCache) Get(key int) int {
	if elem, ok := lru.cache[key]; ok {
		lru.lruList.MoveToFront(elem)
		return elem.Value.(*entry).value
	}
	return -1
}

func (lru *LRUCache) Put(key int, value int) {
	if elem, ok := lru.cache[key]; ok {
		elem.Value.(*entry).value = value
		lru.lruList.MoveToFront(elem)
	} else {
		if len(lru.cache) >= lru.capacity {
			lastElem := lru.lruList.Back()
			delete(lru.cache, lastElem.Value.(*entry).key)
			lru.lruList.Remove(lastElem)
		}
		newElem := lru.lruList.PushFront(&entry{key, value})
		lru.cache[key] = newElem
	}
}

func main() {
	lruCache := NewLRUCache(2)

	lruCache.Put(1, 1)
	lruCache.Put(2, 2)

	fmt.Println(lruCache.Get(1)) // 输出: 1

	lruCache.Put(3, 3)

	fmt.Println(lruCache.Get(2)) // 输出: -1

	lruCache.Put(4, 4)

	fmt.Println(lruCache.Get(1)) // 输出: -1
	fmt.Println(lruCache.Get(3)) // 输出: 3
	fmt.Println(lruCache.Get(4)) // 输出: 4
}

以上代码实现了一个LRU缓存,通过NewLRUCache函数创建一个指定容量的LRUCache对象。Get方法用于获取缓存中指定key的值,如果key不存在则返回-1。Put方法用于向缓存中插入或更新一个key-value对,如果缓存已满则按照LRU算法进行淘汰。

main函数中,我们可以看到如何使用LRUCache对象来进行缓存操作。首先使用Put方法插入两个键值对,然后使用Get方法获取其中一个键的值。接着再插入一个新的键值对,此时由于缓存已满,会淘汰最近最少使用的键。最后使用Get方法验证插入和淘汰的结果。

请注意,此实现使用了Golang标准库中的container/list来维护LRU列表,它提供了双向链表的数据结构。缓存项(entry)作为链表节点的值,并使用map来实现快速的键查找。


LRU缓存的时间复杂度和空间复杂度如下:

  1. 时间复杂度:

    • Get操作的时间复杂度为O(1),因为通过使用哈希表(map)可以快速查找缓存项的位置。
    • Put操作的时间复杂度为O(1),插入或更新缓存项时只需更新哈希表和LRU列表,没有需要遍历的操作。
  2. 空间复杂度:

    • LRU缓存的空间复杂度为O(capacity),其中capacity是LRU缓存的容量。缓存中最多可以存储capacity个缓存项。
    • 此外,还需要额外的空间来存储哈希表和LRU列表。哈希表的空间复杂度为O(capacity),LRU列表的空间复杂度为O(capacity)。

因此,LRU缓存的总体空间复杂度为O(capacity)。