LRU(The Least Recently Used,最近最久未使用算法)是一种常见的缓存算法,在很多分布式缓存系统(如Redis, Memcached)中都有广泛使用。
LRU算法的思想是:如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最久没有访问的数据最先被置换(淘汰)。
LRU算法的描述: 设计一种缓存结构,该结构在构造时确定大小,假设大小为 K,并有两个功能:
- set(key,value):将记录(key,value)插入该结构。当缓存满时,将最久未使用的数据置换掉。
- get(key):返回key对应的value值。
Java 实现:最朴素的思想就是用数组+时间戳的方式,不过这样做效率较低。因此,我们可以用双向链表(LinkedList)+哈希表(HashMap)实现(链表用来表示位置,哈希表用来存储和查找),在Java里有对应的数据结构LinkedHashMap。
下面是针对 Go 语言的 LRU 算法实现。
package problem0146
// 双向链表结构
type LinkNode struct {
key, value int
pre, next *LinkNode
}
// LRU结构
type LRUCache struct {
m map[int]*LinkNode
cap int
head, tail *LinkNode
}
func Constructor(capacity int) LRUCache {
head := &LinkNode{0, 0, nil, nil}
tail := &LinkNode{0, 0, nil, nil}
head.next = tail
tail.pre = head
return LRUCache{make(map[int]*LinkNode, capacity), capacity, head, tail}
}
func (this *LRUCache) moveToHead(node *LinkNode) {
this.removeNode(node)
this.addNode(node)
}
func (this *LRUCache) removeNode(node *LinkNode) {
node.pre.next = node.next
node.next.pre = node.pre
}
func (this *LRUCache) addNode(node *LinkNode) {
head := this.head
node.next = head.next
node.next.pre = node
node.pre = head
head.next = node
}
// 如果有,将这个元素移动到首位置,返回值
// 如果没有,返回-1
func (this *LRUCache) Get(key int) int {
if v, exist := this.m[key]; exist {
this.moveToHead(v)
return v.value
} else {
return -1
}
}
// 如果元素存在,将其移动到最前面,并更新值
// 如果元素不存在,插入到元素首,放入map(判断容量)
func (this *LRUCache) Put(key int, value int) {
tail := this.tail
cache := this.m
if v, exist := cache[key]; exist {
v.value = value
this.moveToHead(v)
} else {
v := &LinkNode{key, value, nil, nil}
if len(this.m) == this.cap {
delete(cache, tail.pre.key)
this.removeNode(tail.pre)
}
this.addNode(v)
cache[key] = v
}
}
思路比代码更重要,想通原理,实现起来 so easy!
: » Go 语言实现 LRU 算法
原创文章,作者:kirin,如若转载,请注明出处:https://blog.ytso.com/252947.html