class Node {
    key: number
    pre : Node | null = null
    next : Node |null = null
    val :number
    constructor(key:number,val:number){
        this.key = key
        this.val = val
    }
 
}
 
class LRUCache {
    //双向链表,最近用的节点放在靠近最近哨兵节点的 next,最不常用的放在最不常用节点的 pre
     head: Node 
     tail: Node
     map:Map<number,Node>
     capacity: number
 
    constructor(capacity: number) {
        this.capacity = capacity
        this.map = new Map()
        this.head = new Node(0,0)
        this.tail = new Node(0,0)
        this.head.next = this.tail;
        this.tail.pre = this.head;
    }
 
    get(key: number): number {
        if(!this.map.has(key)) return -1
        const node = this.map.get(key)
        this.returnToHead(node)
        return node.val
        
    }
 
    put(key: number, value: number): void {
        if(this.map.has(key)){
            const node = this.map.get(key)
            node.val = value
            this.map.set(key,node)
            this.returnToHead(node)
        }else {
            const node = new Node(key,value)
            this.map.set(key,node)
            this.addNodeToHead(node)
            if(this.map.size>this.capacity){
                const lru =  this.removeTail()
                this.map.delete(lru.key)
                
            }
        }
    }
 
    // 头部添加节点
    addNodeToHead(node:Node){
        const curr = this.head.next
        node.pre = this.head
        node.next = curr
        curr.pre = node
        this.head.next = node
    }
    //删除指定地方的节点
    removeNode(node:Node){
        const pre = node.pre
        const next = node.next
        pre.next = next
        next.pre = pre
        return node
    }
    //删除队尾的节点
    removeTail():Node{
        const curr = this.tail.pre
        const node = this.removeNode(curr)
        return node
    }
 
    //把某个节点放到链表头部:即删除这个节点+加到节点头部
    returnToHead(node:Node){
        this.removeNode(node)
        this.addNodeToHead(node)
    }
 
}
 
/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */

golang版本

package geecache
 
import "container/list"
 
type Node struct {
	key   string
	value Value
}
type Value interface {
	Len() int
}
 
type LRU struct {
	maxBytes  int64
	currBytes int64
	cache     map[string]*list.Element
	ll        *list.List
	OnEvicted func(key string, value Value) //删除节点后的回调
}
 
func NewLRU(maxBytes int64) *LRU {
	return &LRU{
		maxBytes:  maxBytes,
		currBytes: 0,
		cache:     make(map[string]*list.Element),
		ll:        list.New(), //双向链表
	}
}
 
func (l *LRU) Get(key string) (value Value, ok bool) {
	//去找是否有这个 key,有的话直接返回,并且把那个节点放在双向链表的队头,没有返回 false
	if ele, ok := l.cache[key]; ok {
		//把这个节点放在队头
		l.ll.MoveToFront(ele)
		kv := ele.Value.(*Node)
		return kv.value, true
	}
	return nil, false
}
 
func (l *LRU) RemoveTail() {
	ele := l.ll.Back()
	if ele != nil {
		l.ll.Remove(ele)
		kv := ele.Value.(*Node)
		delete(l.cache, kv.key)
		l.currBytes -= int64(len(kv.key)) + int64(kv.value.Len())
 
		if l.OnEvicted != nil {
			l.OnEvicted(kv.key, kv.value)
		}
	}
}
 
func (l *LRU) Put(key string, val Value) {
	//看 cache 有没有这个节点,有的话直接更新到队头,并更新这个节点的 val和内存大小,没有的话直接新增一个节点到队头,并且如果超出了最大内存,直接删除节点直到小于最大内存位置
	if ele, ok := l.cache[key]; ok {
		//有
		l.ll.MoveToFront(ele)
		kv := ele.Value.(*Node)
		//更新内存的值
		l.currBytes += int64(val.Len()) - int64(kv.value.Len())
		//更新缓存的值
		kv.value = val
 
	} else {
		//没有,把这个节点加进去
		node := Node{key, val}
		ele := l.ll.PushFront(&node)
		l.cache[key] = ele
		l.currBytes += int64(len(key)) + int64(val.Len())
	}
	//while 循环,无论是更新val 还是新增节点,都可能超出内存
	for l.maxBytes != 0 && l.maxBytes < l.currBytes {
		l.RemoveTail()
	}
}