手撕LRU代码
程序员文章站
2024-03-21 21:47:52
...
原理
LRU(Least Recently Used)最近最少使用,用于缓存淘汰策略,就是把最近最少使用的数据移除内存,以加载其他数据
- 添加元素时,放到链表头
- 缓存命中将元素移动到链表中
- 缓存满了之后,将链表尾的元素删除
原理清楚了,代码其实就是双向链表和map,然后根据需求写代码即可
代码
package main
import (
"container/list"
"fmt"
"sync"
)
type LRU struct {
max int //存储key的最大数量
list *list.List //双向链表
Call func(key interface{}, value interface{}) //淘汰kv时的回调函数
cache map[interface{}]*list.Element //缓存
mu *sync.Mutex //互斥锁
}
type Node struct {
Key interface{}
Val interface{}
}
// NewLRU 返回一个LRU的实例
func NewLRU(len int) *LRU {
return &LRU{
max: len,
list: list.New(),
Call: nil,
cache: make(map[interface{}]*list.Element),
mu: new(sync.Mutex),
}
}
// Add 添加一个kv到缓存中
func (lru *LRU) Add(key, val interface{}) error {
lru.mu.Lock()
defer lru.mu.Unlock()
//如果存在则更新,并将结点移到最前面
if e, ok := lru.cache[key]; ok {
e.Value.(*Node).Val = val
lru.list.MoveToFront(e)
return nil
}
//如果不存在则头插到双向链表中
e := lru.list.PushFront(&Node{
Key: key,
Val: val,
})
//添加至缓存中
lru.cache[key] = e
//如果元素的数量超过最大值了,那么把末端的淘汰
if lru.max != 0 && lru.list.Len() > lru.max {
if e := lru.list.Back(); e != nil {
lru.list.Remove(e)
node := e.Value.(*Node)
delete(lru.cache, node.Key)
if lru.Call != nil {
lru.Call(node.Key, node.Val)
}
}
}
return nil
}
func (lru *LRU) Get(key interface{}) (val interface{}, ok bool) {
lru.mu.Lock()
defer lru.mu.Unlock()
//如果存在,先把该kv移到链表头部再返回
if e, ok := lru.cache[key]; ok {
lru.list.MoveToFront(e)
return e.Value.(*Node).Val, true
}
return
}
func (lru *LRU) GetAll() (data []*Node) {
lru.mu.Lock()
defer lru.mu.Unlock()
for _, v := range lru.cache {
data = append(data, v.Value.(*Node))
}
return data
}
func (lru *LRU) Del(key interface{}) {
lru.mu.Lock()
defer lru.mu.Unlock()
if e, ok := lru.cache[key]; ok {
lru.list.Remove(e)
node := e.Value.(*Node)
delete(lru.cache, node.Key)
if lru.Call != nil {
lru.Call(node.Key, node.Val)
}
}
}
func main() {
lru := NewLRU(3)
lru.Add("w", "1")
lru.Add("x", "2")
lru.Add("f", "3")
lru.Add("c", "4")
lru.Add("s", "5")
for _, node := range lru.GetAll() {
fmt.Println(node)
}
fmt.Println("~~~分割线~~~")
lru.Del("f")
for _, node := range lru.GetAll() {
fmt.Println(node)
}
fmt.Println("~~~分割线~~~")
lru.Add("qq", "68725032")
for _, node := range lru.GetAll() {
fmt.Println(node)
}
}
上一篇: 数据结构与算法实践系列文章(八)散列