ZBLOG

lru算法

LRU(Least Recently Used,最近最少使用)算法是一种常用的缓存替换策略,用于管理缓存中的数据。其基本思想是:如果一个数据在最近被访问过,那么将来被访问的可能性也更高;反之,如果一个数据在很久以前被访问过而现在没有使用,说明它不太可能再被使用,因此可以将其淘汰。

LRU 算法的基本步骤

  1. 初始化

    • 创建一个固定大小的缓存。
    • 使用哈希表(或字典)快速查找缓存中的数据。
    • 使用双向链表维护数据的使用顺序。
  2. 获取操作 (get(key)):

    • 如果该键存在于缓存中:
      • 将对应节点移动到双向链表头部,表示它是最近使用的数据。
      • 返回该节点的值。
    • 如果该键不存在,返回-1或其他指示未找到的数据。
  3. 插入/更新操作 (put(key, value)):

    • 如果该键已经存在:
      • 更新其值,并将对应节点移动到双向链表头部。
    • 如果该键不存在且缓存未满:
      • 在链表头部插入新节点,同时在哈希表中记录其位置。
    • 如果缓存已满:
      • 淘汰双向链表尾部的数据(即最久未使用的数据),并从哈希表中删除对应项。
      • 将新节点插入到头部,同时更新哈希表。

示例代码

以下是Python实现LRU算法的示例:

  1. class Node:
  2. def __init__(self, key, value):
  3. self.key = key
  4. self.value = value
  5. self.prev = None
  6. self.next = None
  7. class LRUCache:
  8. def __init__(self, capacity: int):
  9. self.capacity = capacity # 缓存容量
  10. self.cache = {} # 哈希表,用于O(1)访问
  11. # 双向链表头尾哨兵节点
  12. self.head = Node(0, 0)
  13. self.tail = Node(0, 0)
  14. self.head.next = self.tail
  15. self.tail.prev = self.head
  16. def _remove(self, node: Node):
  17. """移除指定节点"""
  18. prev_node = node.prev
  19. next_node = node.next
  20. prev_node.next = next_node
  21. next_node.prev = prev_node
  22. def _add_to_head(self, node: Node):
  23. """将节点添加到双向链表的头部"""
  24. node.prev = self.head
  25. node.next = self.head.next
  26. self.head.next.prev = node
  27. self.head.next = node
  28. def get(self, key: int) -> int:
  29. if key in self.cache:
  30. node = self.cache[key]
  31. # 移动到头部并返回值
  32. self._remove(node)
  33. self._add_to_head(node)
  34. return node.value
  35. return -1
  36. def put(self, key: int, value: int) -> None:
  37. if key in this.cache:
  38. # 更新现有节点并移动到头部
  39. existing_node= this.cache[key]
  40. existing_node.value=value
  41. # Move the updated node to head of the list
  42. this._remove(existing_node)
  43. this._add_to_head(existing_node)
  44. else:
  45. newNode=Node(key,value)
  46. if len(this.cache)==this.capacity:
  47. tail=this.tail.prev
  48. this._remove(tail)
  49. del this.cache[tail.key]
  50. this._add_to_head(newNode)
  51. this.cache[key]=newNode
  52. # 示例用法:
  53. lru_cache = LRUCache(2) # 初始化容量为2
  54. lru_cache.put(1, 1) # 缓存为 {1=1}
  55. lru_cache.put(2, 2) # 缓存为 {1=1, 2=2}
  56. print(lru_cache.get(1)) # 返回 1,并将 1 移动到最近使用位置,缓存为 {2=2, 1=1}
  57. lru_cache.put(3, 3) # 淘汰关键字 2,缓存为 {1=1, 3=3}
  58. print(lru_cache.get(2)) # 返回-1 (未找到)
  59. lru_cache.put(4, 4) # 淘汰关键字 1,缓存为 {3=3, 4=4}
  60. print(lru_cache.get(1)) # 返回-1 (未找到)
  61. print(lru_cache.get(3)) # 返回3,并将其移动到最近使用位置,缓存为 {4=4 ,3=3 }
  62. print(lru_cache.get(4)) # 返回4,并将其移动到最近使用位置,缓存为 {3=3 ,4=4 }

总结

LRU算法通过结合哈希表和双向链表,实现了O(1)时间复杂度内完成获取、插入和淘汰操作。这使得LRU成为一种高效且实用的缓存管理策略,在很多场景下得到广泛应用,比如网页浏览器、数据库查询等。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=19661

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?