算法—leetcode—146. LRU 缓存机制

240 阅读3分钟

题目

  1. LRU 缓存机制

题目描述

运用你所掌握的数据结构,设计和实现一个  LRU (最近最少使用) 缓存机制 。 实现 LRUCache 类:

LRUCache(int capacity)以正整数作为容量capacity初始化LRU缓存
int get(int key)如果关键字key存在于缓存中,则返回关键字的值,否则返回 -1。
void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。 当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。

思考

哈希表查找快,但是数据没有固定顺序;链表有顺序之分,插入、删除快,但是查找慢;所以结合一下,形成一种新得数据结构:哈希链表LinkedHashMap

代码

package leetcode

import (
	"encoding/json"
	"log"
)

// 单个节点
type Node struct {
	key  int
	val  int
	prev *Node
	next *Node
}

type DoubleList struct {
	// 链表元素个数
	size int
	// 头尾节点
	head *Node
	tail *Node
}

// InitDoubleList
// 初始化双向链表
func InitDoubleList() *DoubleList {
	list := &DoubleList{
		head: &Node{},
		tail: &Node{},
	}
	list.head.next = list.tail
	list.tail.prev = list.head
	list.size = 0
	return list
}

// AddLast
// 在链表尾部添加节点x,时间复杂度O(1)
func (list *DoubleList) AddLast(x *Node) {

	x.prev = list.tail.prev
	x.next = list.tail

	list.tail.prev.next = x
	list.tail.prev = x
	list.size++
}

// Remove
// 删除链表中x节点(x一定存在)
// 由于是双链表且给得目标Node节点,时间复杂度为O(1)
func (list *DoubleList) Remove(x *Node) {
	// 前一个节点的下一个为x节点得下一个
	x.prev.next = x.next
	// 下一个节点的前一个为x节点的前一个
	x.next.prev = x.prev
	list.size--
}

// RemoveFirst
// 删除链表中第一个节点,并返回该节点,时间复杂度为O(1)
func (list *DoubleList) RemoveFirst() *Node {
	// 校验是否双向链表为空
	if list.head.next == list.tail {
		return nil
	}
	first := list.head.next
	list.Remove(first)
	return first
}

// Size
// 返回链表长度,时间复杂度O(1)
func (list *DoubleList) Size() int {
	return list.size
}

type LRUCache struct {
	hashMap map[int]*Node
	cache   *DoubleList
	cap     int
}

// Constructor
// 初始化
func Constructor(capacity int) LRUCache {
	return LRUCache{
		hashMap: map[int]*Node{},
		cache:   InitDoubleList(),
		cap:     capacity,
	}
}

// makeRecently
// 将key提升为最近使用得
func (this *LRUCache) makeRecently(key int) {
	x, ok := this.hashMap[key]
	// 校验是否存在
	if !ok {
		return
	}
	this.cache.Remove(x)
	this.cache.AddLast(x)
}

// addRecently
// 添加最近使用得元素
func (this *LRUCache) addRecently(key, val int) {
	x := &Node{key: key, val: val}
	// 链表尾部就是最近使用得元素
	this.cache.AddLast(x)
	// 在map中添加key得映射
	this.hashMap[key] = x
}

// deleteKey
// 删除某一个key
func (this *LRUCache) deleteKey(key int) {
	x, ok := this.hashMap[key]
	// 校验是否存在
	if !ok {
		return
	}
	this.cache.Remove(x)
	delete(this.hashMap, key)
}

// removeLeastRecently
// 删除最久未使用的元素
func (this *LRUCache) removeLeastRecently() {
	x := this.cache.RemoveFirst()
	if x == nil {
		return
	}
	key := x.key
	delete(this.hashMap, key)
}

// Get
func (this *LRUCache) Get(key int) int {
	node, ok := this.hashMap[key]
	if !ok {
		return -1
	}
	this.makeRecently(key)
	return node.val
}

// Put
func (this *LRUCache) Put(key int, value int) {
	if _, ok := this.hashMap[key]; ok {
		// 删除旧的数据
		this.deleteKey(key)
		// 新插入的数据为最近使用的数据
		this.addRecently(key, value)
		return
	}

	if this.cap == this.cache.Size() {
		// 删除最近未使用的元素
		this.removeLeastRecently()
	}
	// 添加为最近使用的元素
	this.addRecently(key, value)
}

func (this *LRUCache) Println() {
	if rs, err := json.Marshal(this.hashMap); err == nil {
		log.Println(string(rs))
	}
}

参考

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/lr…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

[算法小抄@付东来]