golang实现lru缓存

简介: golang实现lru缓存

公众号merlinsea


  • 请你设计并实现一个满足  LRU (最近最少使用) 缓存 约束的数据结构。
  • LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1,golang可以返回多关键字,用于标识是否存在
  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字
  • 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行
  • 解题思路
  • 首先要求get(key)需要在O(1)的时间复杂度下获取结果,因此这里可以使用map来存储数据,map的key是一个int类型,map的value是一个地址,这个地址指向真正的节点。
  • 另外由于put操作中在数据量超过capacity的时候需要把最久没有使用到的关键字删除,因此可以知道还需要使用双向链表来记录数据。
  • 当put操作的时候发现lru缓存的容量已经满了的情况,需要将tail 的前驱节点(即最久没有访问过的节点)删除。 这里的双向链表采用了虚拟头节点和尾节点的编程技巧。
  • 为什么使用双向链表
  • 双向链表每个节点都有前驱和后继节点,可以通过链表的顺序关系可以来判断哪些节点是最近使用的,哪些节点是最早使用的。
  • 双向链表中删除某个节点可以保证O(1)的时间复杂度,首先在map中通过key快速定位下节点信息,得到节点信息以后可以把这个节点通过调整指针指向来使其移动到链表中的第一位【表示最近访问过了】。


640.png

  • 代码实现


package lru_cache
// 定义双向链表的节点
type Node struct {
  Key  int
  Val  int
  Pre  *Node
  Next *Node
}
// lru缓存
type LRUCache struct {
  KeyNodeMap map[int]*Node
  Head       *Node
  Tail       *Node
  Capacity   int
}
// 构造器,通过new()可以创建一个指向结构体的指针
func Constructor(capacity int) LRUCache {
  lruCathe := LRUCache{
    KeyNodeMap: make(map[int]*Node),
    Head:       new(Node),
    Tail:       new(Node),
    Capacity:   capacity,
  }
  lruCathe.Head.Next = lruCathe.Tail
  lruCathe.Tail.Pre = lruCathe.Head
  return lruCathe
}
func (this *LRUCache) Get(key int) int {
  nodePtr, ok := this.KeyNodeMap[key]
  if !ok {
    return -1
  }
  // 将结果放到第一个
  this.moveFirst(nodePtr)
  return nodePtr.Val
}
func (this *LRUCache) Put(key int, value int) {
  // 判断是否存在
  nodePtr, ok := this.KeyNodeMap[key]
  if ok {
    // 存在则进行替换
    nodePtr.Val = value
    // 将节点移到最前面
    this.moveFirst(nodePtr)
  } else {
    if this.Capacity == len(this.KeyNodeMap) {
      // 容量已经满了,先删除tail(包括双向链表和map)
      oldNodePtr := this.Tail.Pre
      this.Tail.Pre = oldNodePtr.Pre
      oldNodePtr.Pre.Next = this.Tail
      delete(this.KeyNodeMap, oldNodePtr.Key)
    }
    // 插入
    nodePtr := &Node{
      Key:  key,
      Val:  value,
      Pre:  this.Head,
      Next: this.Head.Next,
    }
    this.Head.Next.Pre = nodePtr
    this.Head.Next = nodePtr
    this.KeyNodeMap[key] = nodePtr
  }
}
 // 将节点nodePtr移动的第一位表示最近访问过的节点
func (this *LRUCache) moveFirst(nodePtr *Node) {
  nodePtr.Pre.Next = nodePtr.Next
  nodePtr.Next.Pre = nodePtr.Pre
  nodePtr.Next = this.Head.Next
  this.Head.Next.Pre = nodePtr
  this.Head.Next = nodePtr
  nodePtr.Pre = this.Head
}
func main() {
  lruCache := lru_cache.Constructor(2)
  lruCache.Put(1, 1)
  lruCache.Put(2, 2)
  v := lruCache.Get(1)
  fmt.Println(v)
  lruCache.Put(3, 3)
  v = lruCache.Get(2)
  fmt.Println(v)
  lruCache.Put(4, 4)
  v = lruCache.Get(1)
  fmt.Println(v)
  v = lruCache.Get(3)
  fmt.Println(v)
  v = lruCache.Get(4)
  fmt.Println(v)
}

golang版本永久算法题训练营~~

奔跑的小梁,公众号:梁霖编程工具库

算法训练营golang专题刷题来啦!!!!

相关文章
|
2月前
|
缓存 算法 前端开发
深入理解缓存淘汰策略:LRU和LFU算法的解析与应用
【8月更文挑战第25天】在计算机科学领域,高效管理资源对于提升系统性能至关重要。内存缓存作为一种加速数据读取的有效方法,其管理策略直接影响整体性能。本文重点介绍两种常用的缓存淘汰算法:LRU(最近最少使用)和LFU(最不经常使用)。LRU算法依据数据最近是否被访问来进行淘汰决策;而LFU算法则根据数据的访问频率做出判断。这两种算法各有特点,适用于不同的应用场景。通过深入分析这两种算法的原理、实现方式及适用场景,本文旨在帮助开发者更好地理解缓存管理机制,从而在实际应用中作出更合理的选择,有效提升系统性能和用户体验。
81 1
|
3月前
|
缓存 Python
在Python中,`functools`模块提供了一个非常有用的装饰器`lru_cache()`,它实现了最近最少使用(Least Recently Used, LRU)缓存策略。
在Python中,`functools`模块提供了一个非常有用的装饰器`lru_cache()`,它实现了最近最少使用(Least Recently Used, LRU)缓存策略。
|
2月前
|
存储 缓存 Java
|
2月前
|
存储 缓存 算法
Python 从零开始实现一个简单的LRU缓存
Python 从零开始实现一个简单的LRU缓存
30 0
|
3月前
|
缓存 算法 前端开发
前端 JS 经典:LRU 缓存算法
前端 JS 经典:LRU 缓存算法
43 0
|
4月前
|
缓存 算法 索引
LeetCode146:LRU缓存
LeetCode146:LRU缓存
28 1
|
5月前
|
缓存 算法 Java
数据结构~缓存淘汰算法--LRU算法(Java的俩种实现方式,万字解析
数据结构~缓存淘汰算法--LRU算法(Java的俩种实现方式,万字解析
|
19天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
2月前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
60 0
|
20天前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群