LRU缓存——双向链表+哈希表

269 阅读1分钟

image.png

小贴士

在双向链表的实现中,使用一个伪头部(dummy head)和伪尾部(dummy tail)标记界限,这样在添加节点和删除节点的时候就不需要检查相邻的节点是否存在。

image.png

步骤

  1. 建立LRUCahe结构体作为实现LRU缓存的对象
  2. 结构体中包含当前大小和容量
  3. 包含map结构和链表结构
  4. map与链表关联
  5. 将功能细分如:初始化LRUCache结构体
  6. 初始化结点,在put时候使用
  7. get,put操作也可以将对链表的操作单独拿出来,如:
  8. 在头节点加节点addToHand (put使用)
  9. 删除节点removeNode (put超出容量时使用)
  10. 移动节点(也就是删除节点+加节点)(重复get使用)
  11. 删除尾节点 (put超出容量时使用)
type LRUCache struct {
    size int
    capacity int
    cache map[int]*LinkedNode
    head,tail *LinkedNode
}

type LinkedNode struct {
    pre,next *LinkedNode
    key,value int
}

func InitLinkedNode(key,value int) *LinkedNode{
    return &LinkedNode{
        key : key,
        value : value,
    }
}

func Constructor(capacity int) LRUCache {
    l := LRUCache{
        capacity : capacity,
        cache : map[int]*LinkedNode{},
        head : InitLinkedNode(0,0),
        tail : InitLinkedNode(0,0),
    }
    l.head.next =  l.tail
    l.tail.pre = l.head
    return l
}


func (this *LRUCache) Get(key int) int {
    if node,ok := this.cache[key]; ok {
        this.moveToHand(node)
        return node.value
    }
    return -1
}


func (this *LRUCache) Put(key int, value int)  {
    node,ok := this.cache[key]
    if  !ok {
        node = InitLinkedNode(key,value)
        this.cache[key] = node
        this.addToHand(node)
        this.size++
        if this.size > this.capacity {
            removed := this.removeTail()
            delete(this.cache,removed.key)
            this.size--
        }
        return
    }
    node.value = value     
    this.moveToHand(node)
}

func (this *LRUCache) addToHand(node *LinkedNode)  {
    node.next = this.head.next
    node.pre = this.head
    this.head.next = node
    node.next.pre = node
}

func (this *LRUCache) removeNode(node *LinkedNode)  {
    node.pre.next =  node.next
    node.next.pre = node.pre
}

func (this *LRUCache) moveToHand(node *LinkedNode)  {
    this.removeNode(node)
    this.addToHand(node)
}

func (this *LRUCache) removeTail() *LinkedNode {
    node := this.tail.pre 
    this.removeNode(node)
    return node
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * obj := Constructor(capacity);
 * param_1 := obj.Get(key);
 * obj.Put(key,value);
 */