golang sample code to implement the LRU cache elimination algorithm

  • 2020-06-23 00:35:20
  • OfStack

LRU cache elimination algorithm

LRU stands for the least recently used strategy, which is to weed out data based on historical access to the data. The core idea is that "if the data has been accessed recently, it is more likely to be accessed in the future."

Bi-directional linked list implementation LRU

All the positions of Cache are connected with a double-linked list. When a position is accessed (get/put), the position is adjusted to the head of the linked list by adjusting the direction of the list. The newly added Cache is directly added to the head of the linked list.

In this way, after many operations, the most recently accessed (get/put) will be moved towards the head of the list, while those that are not accessed will be moved towards the rear of the list, with the tail representing the least recently used Cache.

When the cache capacity limit is reached, the last position of the list is the least accessed Cache, we just need to remove the last Cache to continue adding new Cache.

Code implementation


type Node struct {
  Key int
  Value int
  pre *Node
  next *Node
}

type LRUCache struct {
  limit int
  HashMap map[int]*Node
  head *Node
  end *Node
}

func Constructor(capacity int) LRUCache{
  lruCache := LRUCache{limit:capacity}
  lruCache.HashMap = make(map[int]*Node, capacity)
  return lruCache
}

func (l *LRUCache) Get(key int) int {
  if v,ok:= l.HashMap[key];ok {
    l.refreshNode(v)
    return v.Value
  }else {
    return -1
  }
}

func (l *LRUCache) Put(key int, value int) {
  if v,ok := l.HashMap[key];!ok{
    if len(l.HashMap) >= l.limit{
      oldKey := l.removeNode(l.head)
      delete(l.HashMap, oldKey)
    }
    node := Node{Key:key, Value:value}
    l.addNode(&node)
    l.HashMap[key] = &node
  }else {
    v.Value = value
    l.refreshNode(v)
  }
}

func (l *LRUCache) refreshNode(node *Node){
  if node == l.end {
    return
  }
  l.removeNode(node)
  l.addNode(node)
}

func (l *LRUCache) removeNode(node *Node) int{
  if node == l.end {
    l.end = l.end.pre
  }else if node == l.head {
    l.head = l.head.next
  }else {
    node.pre.next = node.next
    node.next.pre = node.pre
  }
  return node.Key
}

func (l *LRUCache) addNode(node *Node){
  if l.end != nil {
    l.end.next = node
    node.pre = l.end
    node.next = nil
  }
  l.end = node
  if l.head == nil {
    l.head = node
  }
}

Related articles: