LRU算法的设计
lru就是一种淘汰策略,当内存不够的时候,淘汰掉最近最少使用的内个。我们可以把整个cache看做一个队列,假设每次都是从队尾进入,那么队头的内个就是最近不使用的。
显然这个cache满足以下几个特点:
- cache中的元素都是有序的。区分最近有没有使用,当容量满了之后删除最近没有使用的内个
- 每次需要快速定位到内个需要背删除的元素,并找到其存储的值
- 每次访问了cache中的某个key,需要将元素变为最近使用,也就是需要快速删除和插入元素
普通的数据结构是无法满足上述特点的,我们可以用 哈希表+双向链表 这个算法核心也是这个
哈希表:map,存储key -> value 用于快速找到对应的值
双向链表:用于快速删除插入元素,由多个node节点组成,每个node节点中元素是key-value
代码实现
首先定义node结构体
//双向链表 中的每一个节点的结构体type Node struct {key,value intprev,next *Node}
再定义双向链表,并且实现链表的插入删除等功能
//双向链表结构体type DoubleList struct {//虚拟头尾节点head,tail *Nodesize int}//在链表尾部添加节点nodefunc (dl *DoubleList) addLast (node *Node) {node.prev = dl.tail.prev //新加的node节点前指针 指向 链表的尾部的前指针。node.next = dl.taildl.tail.prev.next = nodedl.tail.prev = nodedl.size++}//删除链表中的节点node 当put一个key存在value不同时,做的是先删除后添加的操作,这样新加的永远在队尾func (dl *DoubleList) remove (node *Node) {node.prev.next = node.nextnode.next.prev = node.prevdl.size--}//删除链表第一个真实元素,并且返回该元素 这就是删除最近未使用的功能func (dl *DoubleList) removeFirst () *Node{if dl.head.next == dl.tail {return nil}first := dl.head.nextremove(first)return first}
前置的双向链表准备完毕了,链表功能也都实现了,现在我们要定义LRU的核心的结构 “哈希表+双向链表”
type LRUcache struct {//map 用于快速找到精确的key对应的valuecacheMap map[int]*Node//双向链表cacheList *DoubleList//最大容量capacity int}
至此,就可以完成功能代码了
func Constructor(capacity int) LRUCache {lru := LRUCache{cacheMap : map[int]*Node{},cacheList: &DoubleList{head: &Node{key: 0,value: 0}, //虚拟一个头节点tail: &Node{key: 0,value: 0}, //虚拟一个尾结点},capacity:capacity,}//把双向链表虚拟头尾节点 链接起来lru.cacheList.head.next = lru.cacheList.taillru.cacheList.tail.prev = lru.cacheList.headreturn lru}func (this *LRUCache) Get(key int) int {//判断map中是否存在keyif node,ok := this.cacheMap[key]; ok {//存在的话,将这个节点变成最近使用过,也就是先删除,在放到队尾this.cacheList.remove(node)this.cacheList.addLast(node)return node.value}return -1}func (this *LRUCache) Put(key int, value int) {//put复杂很多,如果key存在,那就删除之前的,将现在的放入队尾。如果不存在,需要插入队尾并判断容量if node,ok := this.cacheMap[key]; ok {this.cacheList.remove(node)}if this.capacity == this.cacheList.size {first := this.cacheList.removeFirst()delete(this.cacheMap,first.key)}newNode := &Node{key:key,value:value}this.cacheList.addLast(newNode)this.cacheMap[key] = newNode}
