本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1、LRU算法含义
LRU算法,全称为least recently used,也即最近最久未使用算法。当LRU缓存达到上限时,该算法会将最久未使用的数据淘汰掉,从而腾出空间给即将添加的数据。
2、LRU算法的设计
由于LRU算法结构要保存顺序结构,又要能快速的查询和删除。我们知道链表可以实现快速的删除和增加元素,但是查询是低效的。 而哈希表的查找是O(1)时间复杂度的。 所以我们可以将这两种数据结构结合起来。
3、LRU算法的基本实现
首先,定义双链表节点。
class ListNode:
def __init__(self, key, value):
self.key = key
self.value = value
self.next = None
self.prev = None
class LRUCache:
def __init__(self, capacity: int):
self.size = capacity
# 定义双链表的头和尾结点
self.head = ListNode(0, 0)
self.tail = ListNode(0, 0)
self.head.next = self.tail
self.tail.prev = self.head
self.map = dict()
def get(self, key: int) -> int:
# 节点不存在时
if key not in self.map:
return -1
# 通过map找到相关节点
node = self.map[key]
# 删除节点,并放在链表最后
# 在实现时可以先考虑要实现的逻辑,具体函数内容在来实现。
self.removeNode(node)
self.addLast(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.map:
# 同查询,将节点提到最后并同时更新值。
node = self.map[key]
self.removeNode(node)
# 更新值
node.value = value
# 添加到末尾
self.addLast(node)
else:
# 判断是否超出容量。
if len(self.map) >= self.size:
self.removeFirst()
node = ListNode(key, value)
self.addLast(node)
def removeNode(self, node):
if self.head.next == self.tail:
return
prev = node.prev
prev.next = node.next
node.next.prev = prev
node.prev = None
node.next = None
def removeFirst(self):
if self.head.next == self.tail:
# 空链表,不处理
return
tmp = self.head.next
self.head.next = tmp.next
tmp.next.prev = self.head
# 删除map中的元素
self.map.pop(tmp.key)
return tmp
def addLast(self, node):
prev = self.tail.prev
prev.next = node
node.prev = prev
node.next = self.tail
self.tail.prev = node
# 在map中添加
self.map[node.key] = node
4、总结
每种数据结构有其特定的特征,在实际的编码过程中,根据实际问题,我们可以尝试将不同的数据结构结合起来形成一种“新”的数据结构来解决问题。 这种想法和思想还是很有趣的。 在android中sdk源码使用LinkedHashMap也实现了Lru的算法,可以学习一下。