实现LRU缓存(Go语言)

162 阅读2分钟

题目要求

请你设计并实现一个满足LRU (最近最少使用) 缓存约束的数据结构。

  • > 实现 LRUCache 类:
    • > LRUCache(int capacity) 以正整数作为容量capacity初始化LRU缓存。
  • > int get(int key) 如果关键字key存在于缓存中,则返回关键字的值,否则返回-1。
  • > void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值value;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该逐出最久未使用的关键字。
  • > 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
type LRUCache struct { //定义表示缓存对象的结构体
    size int //当前大小
    capacity int //最大容量
    cache map[int]*DLinkedNode //哈希
    head, tail *DLinkedNode //双链表
}

type DLinkedNode struct { //双链表节点
    key, value int
    prev, next *DLinkedNode
}

//func 函数名(形式参数列表)(返回值列表)
func initDLinkedNode(key, value int) *DLinkedNode { //双链表节点初始化

    return &DLinkedNode{
        key: key,
        value: value,
    }
}

func Constructor(capacity int) LRUCache { //构造器,初始化LRU的结构,实际就是哈希+链表的整合
    l := LRUCache{ //结构体内属性的初始化
        cache: map[int]*DLinkedNode{}, //map类型的初始化
        head: initDLinkedNode(0, 0),
        tail: initDLinkedNode(0, 0),
        capacity: capacity,
    }
    l.head.next = l.tail
    l.tail.prev = l.head
    return l
}

//从哈希链表中取
func (this *LRUCache) Get(key int) int { //定义方法,接收者是LRUCache,这里的this只是变量名
    if _, ok := this.cache[key]; !ok { //固定用法,语义:用来判断是否为空
        return -1
    }
    node := this.cache[key] //定义node,是map中key对应的value,类型是DLinkedNode
    this.moveToHead(node) //刚使用过,放到最上面
    return node.value
}

//放入哈希链表中,put的逻辑稍微复杂一点
//put:将该节点,做成双向链表节点,加入到map中,放到最近位置
func (this *LRUCache) Put(key int, value int)  {
    if _, ok := this.cache[key]; !ok { //if的这个格式
        node := initDLinkedNode(key, value) //初始化双向链表节点
        this.cache[key] = node //将该节点加入当前LRUCache对象的map中
        this.addToHead(node) //将该节点加到head后
        this.size++ //当前LRUCache大小+1
        if this.size > this.capacity { //判断当前节点是否大于最大容量,若大于,则移除末尾位置节点
            removed := this.removeTail()
            delete(this.cache, removed.key)
            this.size--
        }
    } else { //若存在,更新数值,将该节点移动到最前面
        node := this.cache[key] //定义该key值对应的node
        node.value = value //修改node中的value
        this.moveToHead(node)
    }
}

//将add与remove的api再抽象一层出来,就是双向节点的一些增删
func (this *LRUCache) addToHead(node *DLinkedNode) { //将node节点移动到最前面,即head之后,head.next之前
    node.prev = this.head
    node.next = this.head.next
    this.head.next.prev = node
    this.head.next = node
}

func (this *LRUCache) removeNode(node *DLinkedNode) { //将node移走
    node.prev.next = node.next
    node.next.prev = node.prev
}

func (this *LRUCache) moveToHead(node *DLinkedNode) { //将刚使用过的node移动到head后
    this.removeNode(node)
    this.addToHead(node)
}

func (this *LRUCache) removeTail() *DLinkedNode { //移除tail前的节点
    node := this.tail.prev
    this.removeNode(node)
    return node
}