LRU算法基于循环双链表+Map和JS的Map类型的两种实现方式

LRU

最近最少使用算法,操作系统中典型的Cache替换算法

146. LRU 缓存

方法一

循环双链表+map

规则如下

插入时,若key存在,更新值,并把节点移动到链表尾部

插入时,key不存在,若未达到capacity最大值,放入链表尾部

插入时,key不在,若达到capacity最大值,删除链表头部,插入链表尾部

获取值时,若不存在,直接返回-1

若值存在,把节点移动到尾部,然后返回对应值

function Link(key, val){

this.val = val

this.key = key

this.next = null

this.prior = null

}

/**

* @param {number} capacity

*/

var LRUCache = function(capacity) {

this.capacity = capacity

this.map = new Map()

this.size = 0

this.head = new Link(0,0)

this.head.next = this.head

this.head.prior = this.head

};

LRUCache.prototype.moveToTail = function(node){

if(node !== this.head.prior){

// delete

node.next.prior = node.prior

node.prior.next = node.next

// append

node.next = this.head

node.prior = this.head.prior

this.head.prior.next = node

this.head.prior = node

}

}

/**

* @param {number} key

* @return {number}

*/

LRUCache.prototype.get = function(key) {

if(!this.map.has(key)){

return -1

}

let node = this.map.get(key)

this.moveToTail(node)

return node.val

};

/**

* @param {number} key

* @param {number} value

* @return {void}

*/

LRUCache.prototype.put = function(key, value) {

if(this.map.has(key)){

let node = this.map.get(key)

node.val = value

this.moveToTail(node)

}else{

let node = new Link(key, value)

this.map.set(key, node)

// append

node.next = this.head

node.prior = this.head.prior

this.head.prior.next = node

this.head.prior = node

if(this.size >= this.capacity){

let key = this.head.next.key

this.map.delete(key)

// delete front

this.head.next.next.prior = this.head

this.head.next = this.head.next.next

}else{

this.size++

}

}

};

方法二

js的Map有个特点,Map.prototype.keys()的遍历顺序就是插入顺序,可以替代方法一中的循环双链表

/**

* @param {number} capacity

*/

var LRUCache = function(capacity) {

this.capacity = capacity

this.map = new Map()

};

/**

* @param {number} key

* @return {number}

*/

LRUCache.prototype.get = function(key) {

if(!this.map.has(key)){

return -1

}

let val = this.map.get(key)

this.map.delete(key)

this.map.set(key, val)

return val

};

/**

* @param {number} key

* @param {number} value

* @return {void}

*/

LRUCache.prototype.put = function(key, value) {

if(this.map.has(key)){

this.map.delete(key)

}

this.map.set(key, value)

if(this.map.size > this.capacity){

this.map.delete(this.map.keys().next().value)

}

};

方法三

计数模拟

规则如下

get或者put命中时,计数器清零,比其低的计数器加一,其余不变

put未命中且而含有空闲,计数器置为0,其余全加1

put未命中,且空间满时,淘汰掉计数值为capacity-1的块,新的块计数器置0,其余全加一