Skip to content

LRU

LRU算法也算是最经典的面试算法之一了,其实本身就是一个双向链表。 链表本身分为单向链表、双向链表、循环链表,之前是把双向链表 + 循环链表 搞混了,这两个本质上还是不一样的

经典lru

其实核心还是一个双向链表 + map 核心就是一个双向链表的节点 + 一个map快速判断是否存在 还有一些删除和新增的操作

go
// 定义一个双向链表的结构
// 这个双向链表中的值有key,value
type DLinkedNode struct {
	key, value int
	prev       *DLinkedNode
	next       *DLinkedNode
}

type LRUCache struct {
	head *DLinkedNode
	tail *DLinkedNode
	//根据值获取节点
	cacheMap map[int]*DLinkedNode
	capacity int //上限容量
	size     int //当前存储容量
}

func initNode(k, v int) *DLinkedNode {
	return &DLinkedNode{
		key:   k,
		value: v,
	}
}

func Constructor(capacity int) LRUCache {
	l := LRUCache{
		head:     initNode(0, 0),
		tail:     initNode(0, 0),
		capacity: capacity,
		cacheMap: map[int]*DLinkedNode{},
	}
	//定义好双向链表
	l.head.next = l.tail
	l.tail.prev = l.head
	return l
}

func (this *LRUCache) Get(key int) int {
	node, ok := this.cacheMap[key]
	if !ok {
		return -1
	}
	this.removeToHead(node)
	return node.value
}

func (this *LRUCache) Put(key int, value int) {
	node, ok := this.cacheMap[key]
	//注意下历史node的复用

	if !ok {
		newNode := initNode(key, value)
		//如果不存在,则直接插入首位
		this.addToHead(newNode)
		this.size++
		this.cacheMap[key] = newNode
		if this.size > this.capacity {
			//如果容量超了
			deleteNode := this.removeTail()
			delete(this.cacheMap, deleteNode.key)
			this.size--
		}
	} else {
		node.value = value
		this.removeToHead(node)
		this.cacheMap[key] = node
	}

}

//其实一些细节也挺有意思的

// 记录双向链表的一些操作,是否需要删除由业务层去决定
// 需要定义一些双向链表的操作,比如头部插入数据,尾部删除数据
func (this *LRUCache) addToHead(node *DLinkedNode) {
	//新插入的节点的指针的指向
	node.next = this.head.next
	node.prev = this.head

	//头部节点的指针走向
	this.head.next.prev = node
	this.head.next = node
}

func (this *LRUCache) removeFromTail() {
	this.tail.prev.next = this.tail.next
	this.tail.next.prev = this.tail.prev
}

// 需要返回相关的节点
func (this *LRUCache) removeTail() *DLinkedNode {
	node := this.tail.prev
	this.removeNode(node)
	return node
}

// 删除节点
func (this *LRUCache) removeNode(node *DLinkedNode) {
	node.prev.next = node.next
	node.next.prev = node.prev
}

// 要删除里面的节点
func (this *LRUCache) removeToHead(node *DLinkedNode) {
	this.removeNode(node)
	this.addToHead(node)
}

变种1

带过期时间的LRU