LRU算法的简易实现

LRU全称Least Recently Used,也就是 最近最少使用的意思,是一种内存管理算法,该算法最早应用于 Linux操作系统。
这个算法基于一种假设:长期不被使 用的数据,在未来被用到的几率也不大。因此,当数据所占内存达 到一定阈值时,我们要移除掉最近最少被使用的数据。
LRU算法中,使用了一种有趣的数据结构,这种数据结构叫作哈希 链表。

我们都知道,哈希表是由若干个Key-Value组成的。在“逻辑”上,这些 Key-Value是无所谓排列顺序的,谁先谁后都一样。

在哈希链表中,这些Key-Value不再是彼此无关的存在,而是被一个链 条串了起来。每一个Key-Value都具有它的前驱Key-Value、后继Key- Value,就像双向链表中的节点一样。


依靠哈希链表的有序性,我们可以把 Key-Value按照最后的使用时间进行排序。

LRU算法的基本思路

  1. 假设使用哈希链表来缓存用户信息,目前缓存了4个用户,这4个用户
    是按照被访问的时间顺序依次从链表右端插入的。

  2. 如果这时业务方访问用户5,由于哈希链表中没有用户5的数据,需要
    从数据库中读取出来,插入到缓存中。此时,链表最右端是最新被访问
    的用户5,最左端是最近最少被访问的用户1。

  3. 接下来,如果业务方访问用户2,哈希链表中已经存在用户2的数据,
    这时我们把用户2从它的前驱节点和后继节点之间移除,重新插入链表
    的最右端。此时,链表的最右端变成了最新被访问的用户2,最左端仍
    然是最近最少被访问的用户1

  1. 接下来,如果业务方请求修改用户4的信息。同样的道理,我们会把
    用户4从原来的位置移动到链表的最右侧,并把用户信息的值更新。这
    时,链表的最右端是最新被访问的用户4,最左端仍然是最近最少被访
    问的用户1。

  2. 后来业务方又要访问用户6,用户6在缓存里没有,需要插入哈希链表
    中。假设这时缓存容量已经达到上限,必须先删除最近最少被访问的数
    据,那么位于哈希链表最左端的用户1就会被删除,然后再把用户6插入
    最右端的位置。

代码实现

package algorithm


type lruNode struct {
   key  interface{}
   data interface{}
   next *lruNode
   prev *lruNode
}

type LruCache struct {
   limit int
   head  *lruNode
   end   *lruNode
   value map[interface{}]*lruNode
}


func (l *LruCache) Get(key interface{}) (interface{},bool) {
   a,b := l.value[key]
   return a,b
}


func (l *LruCache) Add(key interface{}, value interface{}) {
   if len(l.value) >= l.limit {
      oldKey := l.removeNode(l.head)
      delete(l.value, oldKey)
   }
   node := &lruNode{data: value, key: key}
   if l.end != nil {
      l.end.next = node
      node.prev = l.end
      node.next = nil
   }
   l.end = node
   if l.head == nil {
      l.head = node
   }
   l.value[key] = node
}

func (l *LruCache) removeNode(node *lruNode) interface{} {
   if node == l.head && node == l.end {


   } else if node == l.end {
      l.end = l.end.prev
      l.end.next = nil
   } else if node == l.head {
      l.head = l.head.next
      l.head.prev = nil
   } else {
      node.prev.next = node.next
      node.next.prev = node.prev
   }
   return node.key
}


func NewLruCache(cap int) *LruCache {
   return &LruCache{limit: cap, value: make(map[interface{}]*lruNode)}
}
posted @ 2020-04-30 12:28  lisq  阅读(658)  评论(0编辑  收藏  举报