LRU算法的简易实现

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

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

LRU算法的简易实现

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

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

LRU算法的基本思路

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

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

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

LRU算法的简易实现

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

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

代码实现

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)}
}

相关推荐