blog icon indicating copy to clipboard operation
blog copied to clipboard

带过期时间LRU的js实现

Open rudyxu1102 opened this issue 4 years ago • 0 comments

原理

使用双向链表和哈希表

代码实现

// 链表节点
class Node {
    constructor (key = null, value = null) {
        this.key = key
        this.saveTime = Date.now()
        this.value = value
        this.pre = null
        this.next = null
    }
}

// 双向链表
class List {
    constructor () {
        this.dummyHead = new Node()
        this.dummyTail = new Node
        this.dummyHead.next = this.dummyTail
        this.dummyTail.pre = this.dummyHead
        this.length = 0
    }

    pop () {
        if (!this.length) return
        let node = this.dummyTail.pre
        node.pre.next = this.dummyTail
        this.dummyTail.pre = node.pre
        this.length--
        return node
    }

    unshiftNode (node) {
        let head = this.dummyHead.next
        node.next = head
        head.pre = node
        this.dummyHead.next = node
        node.pre = this.dummyHead
        this.length++
    }

    removeNode (node) {
        node.pre.next = node.next
        node.next.pre = node.pre
        this.length--
    }

    moveToHead (node) {
        this.removeNode(node)
        this.unshiftNode(node)
    }
}

// LRU缓存
class LRU {
    constructor (size, expire = 1000) {
        this.size = size
        this.expire = expire
        this.map = new Map()
        this.list = new List()
    }

    put (key, value) {
        if (this.map.has(key)) {
            let node = this.map.get(key)
            node.value = value
            this.list.moveToHead(node)
        } else {
            let node = new Node(key, value)
            this.map.set(key, node)
            this.list.unshiftNode(node)
            if (this.list.length > this.size) {
                let node = this.list.pop()
                this.map.delete(node.key)
            }
        }
    }

    get (key) {
        let node = this.map.get(key)
        if (!node) {
            return -1
        }
        if (Date.now() - node.saveTime <= this.expire) {
            this.list.moveToHead(node)
            return node.value
        } else {
            this.list.removeNode(node)
            this.map.delete(key)
            return -1
        }
    }
}

// 测试
let lru = new LRU(2) 
lru.put(1, 1)
lru.put(2, 2)
lru.put(3, 3)
let item = lru.get(1)
console.log(item) // -1

let ele = lru.get(3)
console.log(ele) // 3
setTimeout(() => {
    console.log(lru.get(3)) // -1
}, 2000)

参考

rudyxu1102 avatar Feb 21 '21 03:02 rudyxu1102