golang实现LFU缓存算法

简介: golang实现LFU缓存算法

公众号merlinsea


  • 相关内容导航

LRU最近最少使用算法

奔跑的小梁,公众号:梁霖编程工具库golang实现lru缓存


  • 题目描述
  • LFUCache(int capacity) - 用数据结构的容量 capacity 初始化对象
  • int get(int key) - 如果键 key 存在于缓存中,则获取键的值,否则返回 -1
  • void put(int key, int value) - 如果键 key 已存在,则变更其值;如果键不存在,请插入键值对。当缓存达到其容量 capacity 时,则应该在插入新项之前,移除最不经常使用的项。在此问题中,当存在平局(即两个或更多个键具有相同使用频率)时,应该去除 最近最久未使用 的键
  • 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。

  • 示例

640.png

  • 解题思路
  • 参考之前求解LRU的算法思路,改动点是当访问了某个key的时候,这个key需要移动到一个“合适”的位置,这里的合适指的是要按照每个key的访问频次来排序,当频次相同的访问时间越近的key优先级越高。

640.png


  • 代码实现


type Node struct{
    Val int
    Key int
    // 记录每个节点key出现的次数
    Cnt int
    Pre *Node
    Next *Node
}
type LFUCache struct {
    KeyValueMap map[int]*Node
    Head *Node
    Tail *Node
    Capacity int
}
func Constructor(capacity int) LFUCache {
    lfuCache := LFUCache{
        KeyValueMap : make(map[int]*Node),
        Head : new(Node),
        Tail : new(Node),
        Capacity: capacity,
    }
    lfuCache.Head.Next = lfuCache.Tail
    lfuCache.Tail.Pre = lfuCache.Head
    return lfuCache
}
func (this *LFUCache) Get(key int) int {
    nodePtr,ok := this.KeyValueMap[key]
    if !ok {
        return -1
    }
    nodePtr.Cnt++
    // 将nodePtr调整到合适的位置
    this.move(nodePtr)
    return nodePtr.Val
}
func (this *LFUCache) Put(key int, value int)  {
    nodePtr,ok := this.KeyValueMap[key]
    if ok {
        // 说明已经存在了
        nodePtr.Val = value
        nodePtr.Cnt++
        this.move(nodePtr)
    }else{
        if len(this.KeyValueMap) == this.Capacity {
            //定位下待删除的节点
            p := this.Tail.Pre
            // 执行删除
            this.Tail.Pre = p.Pre
            p.Pre.Next = this.Tail
            delete(this.KeyValueMap,p.Key)
        }
        // 构造节点
        newNodePtr := &Node{
            Key : key,
            Val : value,
            Cnt : 1,
            Pre : this.Tail.Pre,
            Next : this.Tail,
        }
        this.Tail.Pre.Next = newNodePtr
        this.Tail.Pre = newNodePtr
        this.KeyValueMap[key] = newNodePtr
        // 移动
        this.move(newNodePtr)
    }
}
// 考虑如何快速定位节点需要移动到的位置
func (this *LFUCache) move(nodePtr *Node){
    p := nodePtr.Pre
    nodePtr.Pre.Next = nodePtr.Next
    nodePtr.Next.Pre = nodePtr.Pre
    // 移动,这里假定越靠近head节点标识这个节点是最近访问过的,因此这里需要在相等的时候p继续向head移动
    for p!=this.Head && nodePtr.Cnt >= p.Cnt {
        p = p.Pre
    }
    // 将nodePtr插入到p的next
    nodePtr.Next = p.Next
    p.Next.Pre = nodePtr
    nodePtr.Pre = p
    p.Next = nodePtr
}


  • 代码优化思路
  • 可以将双向链表做成优先队列,通过优先队列可以保证每次删除的时间复杂度是logn级别,在本次的代码中,在极端的情况下,比如LFU的容量做的无限大的时候,不断进行put操作,会导致move方法的时间复杂度是On


golang版本永久算法题训练营本年最低价~

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

golang算法训练营价格调整通知23年7月8日【本年最低价,后期涨价】

相关文章
|
4月前
|
缓存 算法 NoSQL
【分布式详解】一致性算法、全局唯一ID、分布式锁、分布式事务、 分布式缓存、分布式任务、分布式会话
分布式系统通过副本控制协议,使得从系统外部读取系统内部各个副本的数据在一定的约束条件下相同,称之为副本一致性(consistency)。副本一致性是针对分布式系统而言的,不是针对某一个副本而言。强一致性(strong consistency):任何时刻任何用户或节点都可以读到最近一次成功更新的副本数据。强一致性是程度最高的一致性要求,也是实践中最难以实现的一致性。单调一致性(monotonic consistency):任何时刻,任何用户一旦读到某个数据在某次更新后的值,这个用户不会再读到比这个值更旧的值。
416 0
|
6天前
|
缓存 算法
LRU(Least Recently Used)算法是一种常用的计算机缓存替换算法
LRU算法是基于页面使用频率的缓存策略,优先淘汰最近最久未使用的页面。实现可采用双向链表或数组,前者灵活,后者时间复杂度低。优点是利用时间局部性提高命中率,简单易实现;缺点是占用空间,对循环访问和随机访问场景适应性不佳。
23 0
|
4月前
|
缓存 网络协议 算法
Golang简单实现 分布式缓存+一致性哈希+节点再平衡(gossip + consistent + rebalance)
Golang简单实现 分布式缓存+一致性哈希+节点再平衡(gossip + consistent + rebalance)
72 0
|
12天前
|
存储 缓存 算法
面试遇到算法题:实现LRU缓存
V哥的这个实现的关键在于维护一个双向链表,它可以帮助我们快速地访问、更新和删除最近最少使用的节点,同时使用哈希表来提供快速的查找能力。这样,我们就可以在 O(1) 的时间复杂度内完成所有的缓存操作。哈哈干净利索,回答完毕。
|
1月前
|
缓存 算法 Java
如何实现缓存与LRU算法以及惰性过期
如何实现缓存与LRU算法以及惰性过期
32 1
|
2月前
|
存储 缓存 算法
从0开始回顾数据结构---LRU,LFU算法
题意解释 请为LFU缓存设计一个数据结构。支持两种操作:get和set。 ● get(key) : 如果key在缓存中,则返回key对应的值;否则返回-1; ● put(key, value): 如果key在缓存中,则更新key对应的值;否则插入(key, value),如果缓存已满,则先删除使用频率最小的key,如果有多个key具有相同的使用频率,则应该删除最久未使用的key。 C++代码 class LFUCache { public: struct Node { Node *left, *right; int key, val;
|
3月前
|
存储 缓存 算法
Golang高性能内存缓存库BigCache设计与分析
【2月更文挑战第4天】分析Golang高性能内存缓存库BigCache设计
82 0
|
4月前
|
存储 缓存 算法
数据结构与算法面试题:实现一个 LRU 缓存,支持如下操作:获取值、更新值、删除键值对和插入键值对
数据结构与算法面试题:实现一个 LRU 缓存,支持如下操作:获取值、更新值、删除键值对和插入键值对
30 0
|
4月前
|
缓存 算法
leetcode-460:LFU 缓存
leetcode-460:LFU 缓存
22 0
|
4月前
|
算法 Go
Golang实现Raft一致性算法
Golang实现Raft一致性算法
45 0