面云账户时候问了LRU,具体实现的方式是map+双链表。Set和Get的时间复杂度都是O(1)。完整写一遍复习一下, 仅作记录

/**
* @Author: lzw5399
* @Date: 2021/5/20 22:28
* @Desc: 基于map和双链表实现的LRU算法
*/
package main import "sync" func main() {
lru := NewLRUCache(3) lru.Set(1, 233)
lru.Set(2, 666)
lru.Set(3, 777)
lru.Set(5, 888) lru.Get(2)
} // LRUCache
type LRUCache struct {
capacity int
cache map[int]*LinkedNode
head *LinkedNode
tail *LinkedNode
sync.RWMutex
} type LinkedNode struct {
key, value int
prev, next *LinkedNode
} func NewLRUCache(capacity int) *LRUCache {
return &LRUCache{
capacity: capacity,
cache: make(map[int]*LinkedNode, capacity),
head: nil,
tail: nil,
RWMutex: sync.RWMutex{},
}
} // - key是否已存在
// - 已存在, 将该节点移动到链表头部
// - 未存在, 判断cap是否已满
// - 满
// - 移除链表尾的节点
// - 新的node放入链表头
// - 新的node放入cache的map中
// - 未满
// - 新的node放入链表头
// - 新的node放入cache的map中
func (l *LRUCache) Set(key int, value int) {
l.RLock()
node, exist := l.cache[key]
l.RUnlock()
if exist {
l.moveToHead(node)
return
} node = &LinkedNode{
key: key,
value: value,
} l.Lock()
defer l.Unlock() if l.capacity == len(l.cache) {
removedNode := l.removeTail()
delete(l.cache, removedNode.key)
} l.addToHead(node)
l.cache[key] = node
} // - 从map中获取是否存在
// - 不存在
// - 返回-1
// - 存在
// - 移到链表头部
// - 并返回具体的值
func (l *LRUCache) Get(key int) int {
l.RLock()
node, exist := l.cache[key]
l.RUnlock()
if !exist {
return -1
} l.moveToHead(node)
return node.value
} func (l *LRUCache) moveToHead(node *LinkedNode) {
l.removeNode(node)
l.addToHead(node)
} func (l *LRUCache) removeTail() *LinkedNode {
return l.removeNode(l.tail)
} func (l *LRUCache) removeNode(node *LinkedNode) *LinkedNode {
// 头节点
if node.prev == nil {
l.head = node.next
node.next.prev = nil
return node
} // 尾节点
if node.next == nil {
l.tail = node.prev
node.prev.next = nil
return node
} // 中间节点
node.prev.next = node.next
node.next.prev = node.prev
return node
} func (l *LRUCache) addToHead(node *LinkedNode) {
if l.head == nil {
l.tail = node
} else {
l.head.prev = node
} node.prev = nil
node.next = l.head
l.head = node
}

LRU的map+双链表实现(Go描述)的更多相关文章

  1. 再谈LRU双链表内存管理

    N年前我写了个双链表也发了博客,还添了代码.但是那个代码不但复杂,而且还有有问题的,一直懒得整理,放在空间误导别人.最近在写服务端,今天抽点空补一篇. 关于LRU网上随便搜,有过后端经验的人应该很多都 ...

  2. 双链表的基本实现与讲解(C++描述)

    双链表 双链表的意义 单链表相对于顺序表,确实在某些场景下解决了一些重要的问题,例如在需要插入或者删除大量元素的时候,它并不需要像顺序表一样移动很多元素,只需要修改指针的指向就可以了,其时间复杂度为 ...

  3. JAVA 链表操作:单链表和双链表

    主要讲述几点: 一.链表的简介 二.链表实现原理和必要性 三.单链表示例 四.双链表示例 一.链表的简介 链表是一种比较常用的数据结构,链表虽然保存比较复杂,但是在查询时候比较便捷,在多种计算机语言都 ...

  4. [C++11][数据结构]自己的双链表实现

    这个双链表,是我模仿stl的list制作的,只实现了一些基本功能,像merge,transfer这些就没有实现,用户可以用基本操作来自己做外部实现. 我没有选用stl的[begin,end)迭代器模式 ...

  5. 在单链表和双链表中删除倒数第K个节点

    [说明]: 本文是左程云老师所著的<程序员面试代码指南>第二章中“在单链表和双链表中删除倒数第K个节点”这一题目的C++复现. 本文只包含问题描述.C++代码的实现以及简单的思路,不包含解 ...

  6. Python与数据结构[0] -> 链表/LinkedList[1] -> 双链表与循环双链表的 Python 实现

    双链表 / Doubly Linked List 目录 双链表 循环双链表 1 双链表 双链表和单链表的不同之处在于,双链表需要多增加一个域(C语言),即在Python中需要多增加一个属性,用于存储指 ...

  7. java实现双链表(差点没写吐系列...)

    刚才把单链表写完了,现在又把双链表写了,双链表和单链表的区别就是每个节点有prior和next两个指针,不同于单链表的一个next指针,而且,正是因为有这两个指针,所以双链表可以前后两个方向去移动指针 ...

  8. 数据结构图文解析之:数组、单链表、双链表介绍及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  9. C和指针 第十二章 使用结构和指针 双链表和语句提炼

    双链表中每个节点包含指向当前和之后节点的指针,插入节点到双链表中需要考虑四种情况: 1.插入到链表头部 2.插入到链表尾部 3.插入到空链表中 4.插入到链表内部 #include <stdio ...

  10. C#双链表

    单链表允许从一个结点直接访问它的后继结点,所以, 找直接后继结点的时间复杂度是 O(1).但是,要找某个结点的直接前驱结点,只能从表的头引用开始遍历各结点.如果某个结点的 Next 等于该结点,那么, ...

随机推荐

  1. 7000元才有的高性能显卡配置,ToDesk云电脑只要不到1块!

    高性能显卡不仅仅是游戏玩家的刚需,也是设计师.工程师和剪辑师等专业人士的必备电脑配置.对于追求极致图形处理能力的用户来说,7000元的显卡预算并不罕见.然而,这样的花费对于大多数个人用户和小型企业来说 ...

  2. Machine Learning Week_9 Anomaly Detection and Recommend System

    1. Anomaly Detection I'd like to tell you about a problem called Anomaly Detection. This is a reason ...

  3. redis的主从复制master/slaver

    什么是Redis的复制 ​ 就是我们常说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主. 复制原理 Slave启动成 ...

  4. C#_自定义简单ORM

    一,基本思路:利用C#的标签和反射功能实现自定义轻量级ORM 标签Attribute附着在实体属性或实体类名上,这样可以取到实体对应的表名,属性对应的表字段名,数据类型,是否主键,字段注释等基本信息 ...

  5. 学习JavaScript第二天

    文章目录 1.运算符(操作符) 1.1运算符的分类 1.2算数运算符 1.3递增和递减运算符 1.4比较运算符 1.5逻辑运算符 2.选择结构 2.1if语句 2.1.1语法 2.1.2案例1:判断闰 ...

  6. 如何阅读 CPU 电路图(以 6502 为例)

    开篇 你是否曾对 CPU 的工作原理充满好奇,以及简单的晶体管又是如何组成逻辑门,进而构建出复杂的逻辑电路实现?本文将以知名的 6502 CPU 的电路图为例,介绍如何阅读 CPU 电路图,并向你演示 ...

  7. uniswap v2 类比

    当然,以下是生活中的类比,帮助你理解 Uniswap V2 的核心概念: 1. 自动化做市商(AMM) 生活中的例子:自动售货机 解释:自动售货机内部有一种商品(如饮料)和一定的库存.用户通过投币购买 ...

  8. Flink CDC 与Hudi整合

    介绍 之前写过Flink CDC sink 到 Iceberg中,本篇主要实践如何CDC到hudi中. 什么是hudi? Hudi is a rich platform to build stream ...

  9. Java net.sf.jxls 生成模板 并导出excel

    如果是 maven项目需要引入下面这个就可以 <dependency> <groupId>net.sf.jxls</groupId> <artifactId& ...

  10. .NET 创建动态方法方案及 Natasha V9

    前言 本篇文章前面客观评估了 .NET 创建动态方方案多个方面的优劣,后半部分是 Natasha V9 的新版特性. .NET 中创建动态方法的方案 创建动态方法的不同选择 以下陈列了几种创建动态方法 ...