LRU 实现(层层剖析)

采用 hashmap+ 双向链表

LRU 实现(层层剖析)

我们需要频繁的去调整首尾元素的位置。而双向链表的结构,刚好满足这一点

采用 hashmap+ 双向链表

首先,我们定义一个 LinkNode ,用以存储元素。因为是双向链表,自然我们要定义 prenext。同时,我们需要存储下元素的 keyvalueval 大家应该都能理解,关键是为什么需要存储 key?举个例子,比如当整个cache 的元素满了,此时我们需要删除 map 中的数据,需要通过 LinkNode 中的key 来进行查询,否则无法获取到 key

type LinkNode struct {
   key, val
   pre, next *LinkNode
}

现在有了 LinkNode ,自然需要一个 Cache 来存储所有的 Node。我们定义 cap 为 cache 的长度,m用来存储元素。head 和 tail 作为 Cache 的首尾。

type LRUCache struct {
	m map[int]*LinkNode
	cap int
	head, tail *LinkNode
}

接下来我们对整个 Cache 进行初始化。在初始化 head 和 tail 的时候将它们连接在一起。

 func Constructor(capacity int) LRUCache {
	head := &LinkNode{0, 0, nil, nil}
	tail := &LinkNode{0, 0, nil, nil}
	head.next = tail
	tail.pre = head
	return LRUCache{make(map[int]*LinkNode), capacity, head, tail}

}

现在我们已经完成了 Cache 的构造,剩下的就是添加它的 API 了。因为 Get 比较简单,我们先完成Get 方法。这里分两种情况考虑,如果没有找到元素,我们返回 -1。如果元素存在,我们需要把这个元素移动到首位置上去。

func (this *LRUCache) Get(key int) int {
	head := this.head
	cache := this.m
	if v, exist := cache[key]; exist {
		 v.pre.next = v.next
		 v.next.pre = v.pre 
 		 v.next = head.next
		 head.next.pre = v
		 v.pre = head
		 head.next = v
		 return v.val
		 } else {
			return -1
		 }
}

大概就是下面这个样子(假若 2 是我们 get 的元素)

我们很容易想到这个方法后面还会用到,所以将其抽出。 1

func (this *LRUCache) AddNode(node *LinkNode) {
	head := this.head
	//从当前位置删除
	node.pre.next = node.next
	node.next.pre = node.pre
	//移动到首位置
	node.next = head.next
	head.next.pre = node
	node.pre = head
	head.next = node
}

func (this *LRUCache) Get(key int) int {
	cache := this.m
	if v, exist := cache[key]; exist {
		this.MoveToHead(v)
		return v.val
	} else {
		return -1
	}
}
func (this *LRUCache) Put(key int, value int) {
	head := this.head
	tail := this.tail
	cache := this.m
 	//假若元素存在
	if v, exist := cache[key]; exist {
		//1.更新值
		 v.val = value
		//2.移动到最前
	this.MoveToHead(v)
	} else {
	//TODO
	v := &LinkNode{key, value, nil, nil}
	 v.next = head.next
	 if len(cache) == this.cap {
		//删除最后元素
        delete(cache, tail.pre.key)
        tail.pre.pre.next = tail
        tail.pre = tail.pre.pre
	}
	 v.pre = head
	 head.next.pre = v
	 head.next = v
	 cache[key] = v
	}
}
Tags: LRU
Share: X (Twitter) Facebook LinkedIn