题目要求
请你设计并实现一个满足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
}