Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions Cache/LRUCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
class DoubleLinkedListNode {
// Double Linked List Node built specifically for LRU Cache
constructor (key, val) {
this.key = key
this.val = val
this.next = null
this.prev = null
}
}

class DoubleLinkedList {
// Double Linked List built specifically for LRU Cache
constructor () {
this.head = new DoubleLinkedListNode(null, null)
this.rear = new DoubleLinkedListNode(null, null)
this.head.next = this.rear
this.rear.prev = this.head
}

add (node) {
// Adds the given node to the end of the list (before rear)
const temp = this.rear.prev
temp.next = node
node.prev = temp
this.rear.prev = node
node.next = this.rear
}

remove (node) {
// Removes and returns the given node from the list
const tempLast = node.prev
const tempNext = node.next
node.prev = null
node.next = null
tempLast.next = tempNext
tempNext.prev = tempLast

return node
}
}

class LRUCache {
// LRU Cache to store a given capacity of data
constructor (capacity) {
this.list = new DoubleLinkedList()
this.capacity = capacity
this.numKeys = 0
this.hits = 0
this.miss = 0
this.cache = {}
}

cacheInfo () {
// Return the details for the cache instance [hits, misses, capacity, current_size]
return `CacheInfo(hits=${this.hits}, misses=${this.miss}, capacity=${this.capacity}, current size=${this.numKeys})`
}

set (key, value) {
// Sets the value for the input key and updates the Double Linked List
if (!(key in this.cache)) {
if (this.numKeys >= this.capacity) {
const keyToDelete = this.list.head.next.key
this.list.remove(this.cache[keyToDelete])
delete this.cache[keyToDelete]
this.numKeys -= 1
}
this.cache[key] = new DoubleLinkedListNode(key, value)
this.list.add(this.cache[key])
this.numKeys += 1
} else {
const node = this.list.remove(this.cache[key])
node.val = value
this.list.add(node)
}
}

get (key) {
// Returns the value for the input key and updates the Double Linked List. Returns null if key is not present in cache
if (key in this.cache) {
this.hits += 1
this.list.add(this.list.remove(this.cache[key]))
return this.cache[key].val
}
this.miss += 1
return null
}
}

function main () {
// Example 1 (Small Cache)
const cache = new LRUCache(2)
cache.set(1, 1)
cache.set(2, 2)

console.log(cache.get(1))

cache.set(3, 3)

console.log(cache.get(2)) // cache miss

cache.set(4, 4)

console.log(cache.get(1)) // cache miss
console.log(cache.get(3))
console.log(cache.get(4))

console.log('Example Cache: ', cache.cacheInfo(), '\n')

// Example 2 (Computing Fibonacci Series - 100 terms)
function fib (num, cache = null) {
if (cache) {
const value = cache.get(num)
if (value) { return value }
}
if (num === 1 || num === 2) { return 1 }
const result = fib(num - 1, cache) + fib(num - 2, cache)
if (cache) { cache.set(num, result) }
return result
}

const fibCache = new LRUCache(100)
for (let i = 1; i <= 100; i++) { fib(i, fibCache) }
console.log('Fibonacci Series Cache: ', fibCache.cacheInfo(), '\n')
}

main()