首页 后端开发 Golang golang lru实现

golang lru实现

May 19, 2023 am 10:16 AM

LRU(Least Recently Used)算法是一种常见的缓存替换策略。在缓存达到预设上限时,缓存会自动淘汰最近最少使用的数据,以释放出空间。

在 Golang 中,我们可以使用双向链表和哈希表来实现 LRU 缓存。在本文中,我们将介绍如何使用这两种数据结构实现 LRU 缓存。

双向链表的作用在于维护缓存的数据顺序,每次插入新数据或者访问数据时,都将对该数据进行提前。同时,在缓存达到上限时,我们可以从链表的末端删除最近最少使用的数据。

哈希表的作用在于加速数据的查找,每次进行数据访问时,通过哈希表中存储的数据索引,我们可以快速地查找到相应的缓存数据。因此,我们将在实现过程中对哈希表进行操作。

接下来,我们将讲解如何实现基于双向链表和哈希表的 LRU 缓存。我们定义一个 LRUCache 结构体,并声明链表头和链表尾指针,以及哈希表 map 和缓存容量 capacity。

type LRUCache struct {
    head, tail *entry  // 链表头和链表尾指针
    cache      map[int]*entry  // 哈希表存储缓存中的数据
    capacity   int     // 缓存容量
}
登录后复制

接下来,我们将定义双向链表节点的结构体。

type entry struct {
    key, value int        // 存储节点的键值对
    prev, next *entry    // 前驱和后继指针
}
登录后复制

这里,我们使用 prev 和 next 分别表示节点的前驱和后继指针,key 和 value 分别表示该节点的键值对。

接下来,我们将定义 LRUCache 的构造函数 NewLRUCache,并传入缓存容量 capacity。

func NewLRUCache(capacity int) *LRUCache {
    return &LRUCache{
        cache:    make(map[int]*entry),
        capacity: capacity,
    }
}
登录后复制

在构造函数中,我们将初始化哈希表和缓存容量。

接下来,我们将定义 LRUCache 的 Get 和 Put 方法来实现数据的访问和存储。

Get 方法的实现:

func (c *LRUCache) Get(key int) int {
    if elem, ok := c.cache[key]; ok {
        // 更新节点位置
        c.moveToHead(elem)
        return elem.value
    }
    return -1
}
登录后复制

首先,我们从哈希表中查找是否存在相应的数据,如果存在,则将节点移到链表的头部,并返回节点存储的值。否则,返回 -1。

下面是 moveToHead 方法的实现:

func (c *LRUCache) moveToHead(elem *entry) {
    if elem == c.head {
        return
    } else if elem == c.tail {
        c.tail = elem.prev
    } else {
        elem.prev.next = elem.next
        elem.next.prev = elem.prev
    }

    elem.prev = nil
    elem.next = c.head
    c.head.prev = elem
    c.head = elem
}
登录后复制

该方法接收一个节点指针 elem,用于将该节点移到链表头部。首先,如果该节点已经是链表头部,则返回;否则,如果该节点是链表尾部,则更新链表尾部指针 tail;否则,将该节点从链表中删除,并将该节点放到链表头部。

Put 方法的实现:

func (c *LRUCache) Put(key, value int) {
    if elem, ok := c.cache[key]; ok {
        elem.value = value
        c.moveToHead(elem)
    } else {
        // 创建新节点
        elem := &entry{key: key, value: value}
        c.cache[key] = elem
        if c.head == nil {
            c.head = elem
            c.tail = elem
        } else {
            // 在链表头部插入新节点
            elem.next = c.head
            c.head.prev = elem
            c.head = elem
        }
        // 判断缓存是否达到预设上限
        if len(c.cache) > c.capacity {
            // 删除链表尾部节点和哈希表中的数据
            delete(c.cache, c.tail.key)
            c.tail = c.tail.prev
            c.tail.next = nil
        }
    }
}
登录后复制

首先,我们从哈希表中查找是否存在相应的数据,如果存在,则更新节点存储的值,并调用 moveToHead 方法将该节点移到链表的头部。否则,创建一个新的节点,并将该节点插入到链表的头部。如果缓存达到预设上限,则删除链表的尾部节点和哈希表中的数据。

最后,我们将完整的代码整合到一起:

type LRUCache struct {
    head, tail *entry
    cache      map[int]*entry
    capacity   int
}

type entry struct {
    key, value int
    prev, next *entry
}

func NewLRUCache(capacity int) *LRUCache {
    return &LRUCache{
        cache:    make(map[int]*entry),
        capacity: capacity,
    }
}

func (c *LRUCache) Get(key int) int {
    if elem, ok := c.cache[key]; ok {
        // 更新节点位置
        c.moveToHead(elem)
        return elem.value
    }
    return -1
}

func (c *LRUCache) moveToHead(elem *entry) {
    if elem == c.head {
        return
    } else if elem == c.tail {
        c.tail = elem.prev
    } else {
        elem.prev.next = elem.next
        elem.next.prev = elem.prev
    }

    elem.prev = nil
    elem.next = c.head
    c.head.prev = elem
    c.head = elem
}

func (c *LRUCache) Put(key, value int) {
    if elem, ok := c.cache[key]; ok {
        elem.value = value
        c.moveToHead(elem)
    } else {
        // 创建新节点
        elem := &entry{key: key, value: value}
        c.cache[key] = elem
        if c.head == nil {
            c.head = elem
            c.tail = elem
        } else {
            // 在链表头部插入新节点
            elem.next = c.head
            c.head.prev = elem
            c.head = elem
        }
        // 判断缓存是否达到预设上限
        if len(c.cache) > c.capacity {
            // 删除链表尾部节点和哈希表中的数据
            delete(c.cache, c.tail.key)
            c.tail = c.tail.prev
            c.tail.next = nil
        }
    }
}
登录后复制

在本文中,我们已经介绍了如何使用双向链表和哈希表来实现 LRU 缓存算法。通过这种算法的实现,我们可以有效地管理缓存,优化数据的访问效率。

以上是golang lru实现的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前 By 尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Go语言包导入:带下划线和不带下划线的区别是什么? Go语言包导入:带下划线和不带下划线的区别是什么? Mar 03, 2025 pm 05:17 PM

本文解释了GO的软件包导入机制:命名imports(例如导入“ fmt”)和空白导入(例如导入_ fmt; fmt;)。 命名导入使包装内容可访问,而空白导入仅执行t

Go语言中如何将MySQL查询结果List转换为自定义结构体切片? Go语言中如何将MySQL查询结果List转换为自定义结构体切片? Mar 03, 2025 pm 05:18 PM

本文详细介绍了MySQL查询结果的有效转换为GO结构切片。 它强调使用数据库/SQL的扫描方法来最佳性能,避免手动解析。 使用DB标签和Robus的结构现场映射的最佳实践

Beego框架中NewFlash()函数如何实现页面间短暂信息传递? Beego框架中NewFlash()函数如何实现页面间短暂信息传递? Mar 03, 2025 pm 05:22 PM

本文解释了Beego的NewFlash()函数,用于Web应用程序中的页间数据传输。 它专注于使用newflash()在控制器之间显示临时消息(成功,错误,警告),并利用会话机制。 Lima

如何编写模拟对象和存根以进行测试? 如何编写模拟对象和存根以进行测试? Mar 10, 2025 pm 05:38 PM

本文演示了创建模拟和存根进行单元测试。 它强调使用接口,提供模拟实现的示例,并讨论最佳实践,例如保持模拟集中并使用断言库。 文章

如何定义GO中仿制药的自定义类型约束? 如何定义GO中仿制药的自定义类型约束? Mar 10, 2025 pm 03:20 PM

本文探讨了GO的仿制药自定义类型约束。 它详细介绍了界面如何定义通用功能的最低类型要求,从而改善了类型的安全性和代码可重复使用性。 本文还讨论了局限性和最佳实践

Go语言如何便捷地写入文件? Go语言如何便捷地写入文件? Mar 03, 2025 pm 05:15 PM

本文详细介绍了在GO中详细介绍有效的文件,将OS.WriteFile(适用于小文件)与OS.openfile和缓冲写入(最佳大型文件)进行比较。 它强调了使用延迟并检查特定错误的可靠错误处理。

您如何在GO中编写单元测试? 您如何在GO中编写单元测试? Mar 21, 2025 pm 06:34 PM

本文讨论了GO中的编写单元测试,涵盖了最佳实践,模拟技术和有效测试管理的工具。

如何使用跟踪工具了解GO应用程序的执行流? 如何使用跟踪工具了解GO应用程序的执行流? Mar 10, 2025 pm 05:36 PM

本文使用跟踪工具探讨了GO应用程序执行流。 它讨论了手册和自动仪器技术,比较诸如Jaeger,Zipkin和Opentelemetry之类的工具,并突出显示有效的数据可视化

See all articles