手撸LRU算法

流水的面试题,铁打的LRU算法…今天来打打铁。

LRU算法的设计

lru就是一种淘汰策略,当内存不够的时候,淘汰掉最近最少使用的内个。我们可以把整个cache看做一个队列,假设每次都是从队尾进入,那么队头的内个就是最近不使用的。
显然这个cache满足以下几个特点:

  • cache中的元素都是有序的。区分最近有没有使用,当容量满了之后删除最近没有使用的内个
  • 每次需要快速定位到内个需要背删除的元素,并找到其存储的值
  • 每次访问了cache中的某个key,需要将元素变为最近使用,也就是需要快速删除和插入元素

普通的数据结构是无法满足上述特点的,我们可以用 **哈希表+双向链表 **这个算法核心也是这个

哈希表:map,存储key -> value 用于快速找到对应的值
双向链表:用于快速删除插入元素,由多个node节点组成,每个node节点中元素是key-value

代码实现

首先定义node结构体

//双向链表 中的每一个节点的结构体
type Node struct {
    key,value int
    prev,next *Node
}

再定义双向链表,并且实现链表的插入删除等功能

//双向链表结构体
type DoubleList struct {
    //虚拟头尾节点
    head,tail *Node
    size int
}

//在链表尾部添加节点node
func (dl *DoubleList) addLast (node *Node) {
    node.prev = dl.tail.prev //新加的node节点前指针 指向 链表的尾部的前指针。
    node.next = dl.tail  
    dl.tail.prev.next = node
    dl.tail.prev = node
    dl.size++
}

//删除链表中的节点node 当put一个key存在value不同时,做的是先删除后添加的操作,这样新加的永远在队尾
func (dl *DoubleList) remove (node *Node) {
    node.prev.next = node.next
    node.next.prev = node.prev
    dl.size--
}

//删除链表第一个真实元素,并且返回该元素 这就是删除最近未使用的功能
func (dl *DoubleList) removeFirst () *Node{
    if dl.head.next == dl.tail {
        return nil
    }
    first := dl.head.next
    remove(first)
    return first
}

前置的双向链表准备完毕了,链表功能也都实现了,现在我们要定义LRU的核心的结构 “哈希表+双向链表”

type LRUcache struct {
    //map 用于快速找到精确的key对应的value 
    cacheMap map[int]*Node
    //双向链表
    cacheList *DoubleList
    //最大容量
    capacity int
}

至此,就可以完成功能代码了

func Constructor(capacity int) LRUCache {
	lru := LRUCache{
		cacheMap : map[int]*Node{},
		cacheList: &DoubleList{
			head: &Node{key: 0,value: 0}, //虚拟一个头节点
			tail: &Node{key: 0,value: 0}, //虚拟一个尾结点
		},
		capacity:capacity,
	}
	//把双向链表虚拟头尾节点 链接起来
	lru.cacheList.head.next = lru.cacheList.tail
	lru.cacheList.tail.prev = lru.cacheList.head
	return lru
}


func (this *LRUCache) Get(key int) int {
	//判断map中是否存在key
	if node,ok := this.cacheMap[key]; ok {
		//存在的话,将这个节点变成最近使用过,也就是先删除,在放到队尾
		this.cacheList.remove(node)
		this.cacheList.addLast(node)
		return node.value
	}
	return -1
}


func (this *LRUCache) Put(key int, value int)  {
	//put复杂很多,如果key存在,那就删除之前的,将现在的放入队尾。如果不存在,需要插入队尾并判断容量
	if node,ok := this.cacheMap[key]; ok {
		this.cacheList.remove(node)
	}

	if this.capacity == this.cacheList.size {
		first := this.cacheList.removeFirst()
		delete(this.cacheMap,first.key)
	}
	newNode := &Node{key:key,value:value}
	this.cacheList.addLast(newNode)
	this.cacheMap[key] = newNode
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值