LRU(Least Recent Used)策略:优先淘汰最近最少使用的数据,常用于缓存淘汰机制,如Linux系统的内存淘汰、Redis的缓存淘汰等。
基于哈希表和双向链表实现LRU
核心思路是,利用双向链表存储键值对,哈希表存储键在链表中对应的节点指针,如下图所示
这样的好处是使访问和更新操作时间复杂度都在O(1)。
PUT操作
- 判断哈希表中key是否已存在,如果存在为修改操作:
- 将链表节点修改为新的键值对
- 将节点移到头部
- 如果不存在为新增操作,此时如果容量已满,需要淘汰数据
- 取出链表尾节点,删除哈希表中对应key
- 删除链表尾节点
- 在链表头部添加新的节点
- 将新的链表头节点加到哈希表
- 如果容量没有满,直接添加节点,执行上述步骤3、4即可
GET操作
- 判断哈希表中key是否存在,如果存在将节点移动到链表头部,返回对应的值
- 如果不存在直接返回nil值
Go语言实现
使用Go内建map类型和container包的list(双向链表)
import (
"container/list"
)
type Pair struct {
key int
val int
}
type LRUCache struct {
cap int
list *list.List
kv map[int]*list.Element
}
func Constructor(capacity int) LRUCache {
return LRUCache{
cap: capacity,
list: list.New(),
kv: make(map[int]*list.Element),
}
}
func (this *LRUCache) Get(key int) int {
if v, ok := this.kv[key]; ok == true {
this.list.MoveToFront(v)
return v.Value.(Pair).val
} else {
return -1
}
}
func (this *LRUCache) Put(key int, value int) {
if elem, ok := this.kv[key]; ok == true {
elem.Value = Pair{key: key, val: value}
this.list.MoveToFront(elem)
return
}
if this.list.Len() >= this.cap {
delete(this.kv, this.list.Back().Value.(Pair).key)
this.list.Remove(this.list.Back())
}
this.list.PushFront(Pair{key: key, val: value})
this.kv[key] = this.list.Front()
}
网友评论