LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
- 新数据插入到链表头部;
- 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
- 当链表满的时候,将链表尾部的数据丢弃。
- 最开始时,内存空间是空的,因此依次进入A、B、C是没有问题的
- 当加入D时,就出现了问题,内存空间不够了,因此根据LRU算法,内存空间中A待的时间最为久远,选择A,将其淘汰
- 当再次引用B时,内存空间中的B又处于活跃状态,而C则变成了内存空间中,近段时间最久未使用的
- 当再次向内存空间加入E时,这时内存空间又不足了,选择在内存空间中待的最久的C将其淘汰出内存,这时的内存空间存放的对象就是E->B->D
package main
import "fmt"
type LRUCache struct {
capacity int
mapItem map[int]*Node
head *Node
tail *Node
}
type Node struct {
key int
value int
pre *Node
next *Node
}
func (n *Node) String() string {
return fmt.Sprintf("key:%d --- value:%d\n", n.key, n.value)
}
func Constructor(capacity int) LRUCache {
head := &Node{
key: -1,
value: -1,
pre: nil,
next: nil,
}
tail := &Node{
key: -1,
value: -1,
pre: nil,
next: nil,
}
head.next = tail
tail.pre = head
lru := LRUCache{
capacity: capacity,
mapItem: make(map[int]*Node, capacity),
head: head,
tail: tail,
}
return lru
}
func (this *LRUCache) Get(key int) int {
if v, ok := this.mapItem[key]; ok {
this.MoveToFront(v)
return v.value
}
return -1
}
func (this *LRUCache) Put(key int, value int) {
if this.Get(key) != -1 {
node := this.mapItem[key]
node.value = value
this.MoveToFront(node)
} else {
if len(this.mapItem) < this.capacity {
node := &Node{
key: key,
value: value,
pre: nil,
next: nil,
}
this.AddToFront(node)
this.mapItem[key] = node
} else {
delNode := this.tail.pre
delete(this.mapItem, delNode.key)
this.mapItem[key] = delNode
delNode.key = key
delNode.value = value
this.MoveToFront(delNode)
}
}
}
func (this *LRUCache) AddToFront(node *Node) {
node.next = this.head.next
this.head.next.pre = node
this.head.next = node
node.pre = this.head
}
func (this *LRUCache) MoveToFront(node *Node) {
this.DelNode(node)
this.AddToFront(node)
}
func (this *LRUCache) DelNode(node *Node) {
if node == this.head || node == this.tail {
return
}
node.next.pre = node.pre
node.pre.next = node.next
}
func (this *LRUCache) dump(s string) {
fmt.Println(s)
node := this.head.next
for node != this.tail {
fmt.Print(node)
node = node.next
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* obj := Constructor(capacity);
* param_1 := obj.Get(key);
* obj.Put(key,value);
*/
func main() {
this := Constructor(2)
this.Put(1, 1)
this.dump("111111111111111111")
this.Put(2, 2)
this.dump("2222222222222222")
fmt.Println(this.Get(1))
this.Put(3, 3)
this.dump("333333333333333")
fmt.Println(this.Get(2))
this.Put(4, 4)
this.dump("4444444444444")
fmt.Println(this.Get(1))
fmt.Println(this.Get(3))
fmt.Println(this.Get(4))
}