基于Golang实现LRU
LRU Least Recently Used的缩写
即最近最少使用,在页面置换和缓存过期key的淘汰中有用到
维持了一个map存储每个节点,另外维持了一个双端列表,来实现删除和插入操作
基本结构:
type LinkNode struct { key, val int pre, next *LinkNode } type LRUCache struct { m map[int]*LinkNode // 指向哈希表的指针 cap int // 长度 head, tail *LinkNode // 两个哨兵 } func Constructor(capacity int) LRUCache { //采用虚拟头尾节点,这两个节点始终处于首位,但不计入map中 head := &LinkNode{-1, 0, nil, nil} tail := &LinkNode{-1, 0, nil, nil} head.next = tail tail.pre = head return LRUCache{make(map[int]*LinkNode), capacity, head, tail} }
关键点:首尾节点是虚拟节点,无论怎么插入删除它们都存在,在cap中不会计算这两个节点,删除也是删除tail节点的前一个节点
Get方法:
func (this *LRUCache) Get(key int) int { m := this.m if node, ok := m[key]; ok { this.moveToHead(node) return node.val } return -1 } func (this *LRUCache) moveToHead(node *LinkNode) { if node.pre != nil && node.next != nil{ node.pre.next = node.next node.next.pre = node.pre } node.pre = this.head node.next = this.head.next this.head.next.pre = node this.head.next = node }
Put方法:
func (this *LRUCache) Put(key int, value int) { m := this.m cap := this.cap tail := this.tail if node, ok := m[key]; ok { //插入新的值 node.val = value this.moveToHead(node) } else { newNode := &LinkNode{key, value, nil, nil} if len(m) == cap { rmTail := tail.pre rmTail.pre.next = tail tail.pre =rmTail.pre rmTail.next = nil delete(m, rmTail.key) } this.moveToHead(newNode) m[key] = newNode } }
关键点:由于双向链表的缘故,在插入或者删除时会一定注意检查前后节点的双向指针的指向问题
源码地址
leetcode地址
本文来自博客园,作者:LeeJuly,转载请注明原文链接:https://www.cnblogs.com/peterleee/p/14886339.html