Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7822e8a

Browse files
Added LFU Cache (TheAlgorithms#221)
* Added LFU Cache * Added explaination for the algo * Fixed Typo
1 parent 95d799a commit 7822e8a

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

‎Cache/LFUCache.js‎

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
class DoubleLinkedListNode {
2+
// Double Linked List Node built specifically for LFU Cache
3+
constructor (key, val) {
4+
this.key = key
5+
this.val = val
6+
this.freq = 0
7+
this.next = null
8+
this.prev = null
9+
}
10+
}
11+
12+
class DoubleLinkedList {
13+
// Double Linked List built specifically for LFU Cache
14+
constructor () {
15+
this.head = new DoubleLinkedListNode(null, null)
16+
this.rear = new DoubleLinkedListNode(null, null)
17+
this.head.next = this.rear
18+
this.rear.prev = this.head
19+
}
20+
21+
_positionNode (node) {
22+
// Helper function to position a node based on the frequency of the key
23+
while (node.prev.key && node.prev.freq > node.freq) {
24+
const node1 = node
25+
const node2 = node.prev
26+
node1.prev = node2.prev
27+
node2.next = node1.prev
28+
node1.next = node2
29+
node2.prev = node1
30+
}
31+
}
32+
33+
add (node) {
34+
// Adds the given node to the end of the list (before rear) and positions it based on frequency
35+
const temp = this.rear.prev
36+
temp.next = node
37+
node.prev = temp
38+
this.rear.prev = node
39+
node.next = this.rear
40+
this._positionNode(node)
41+
}
42+
43+
remove (node) {
44+
// Removes and returns the given node from the list
45+
const tempLast = node.prev
46+
const tempNext = node.next
47+
node.prev = null
48+
node.next = null
49+
tempLast.next = tempNext
50+
tempNext.prev = tempLast
51+
52+
return node
53+
}
54+
}
55+
56+
class LFUCache {
57+
// LFU Cache to store a given capacity of data
58+
// The Double Linked List is used to store the order of deletion from the cache
59+
// The rear.prev holds the most frequently used key and the head.next holds the least used key
60+
// When the number of elements reaches the capacity, the least frequently used item is removed before adding the next key
61+
constructor (capacity) {
62+
this.list = new DoubleLinkedList()
63+
this.capacity = capacity
64+
this.numKeys = 0
65+
this.hits = 0
66+
this.miss = 0
67+
this.cache = {}
68+
}
69+
70+
cacheInfo () {
71+
// Return the details for the cache instance [hits, misses, capacity, current_size]
72+
return `CacheInfo(hits=${this.hits}, misses=${this.miss}, capacity=${this.capacity}, current size=${this.numKeys})`
73+
}
74+
75+
set (key, value) {
76+
// Sets the value for the input key and updates the Double Linked List
77+
if (!(key in this.cache)) {
78+
if (this.numKeys >= this.capacity) {
79+
const keyToDelete = this.list.head.next.key
80+
this.list.remove(this.cache[keyToDelete])
81+
delete this.cache[keyToDelete]
82+
this.numKeys -= 1
83+
}
84+
this.cache[key] = new DoubleLinkedListNode(key, value)
85+
this.list.add(this.cache[key])
86+
this.numKeys += 1
87+
} else {
88+
const node = this.list.remove(this.cache[key])
89+
node.val = value
90+
this.list.add(node)
91+
}
92+
}
93+
94+
get (key) {
95+
// Returns the value for the input key and updates the Double Linked List. Returns null if key is not present in cache
96+
if (key in this.cache) {
97+
this.hits += 1
98+
this.list.add(this.list.remove(this.cache[key]))
99+
return this.cache[key].val
100+
}
101+
this.miss += 1
102+
return null
103+
}
104+
}
105+
106+
function main () {
107+
// Example 1 (Small Cache)
108+
const cache = new LFUCache(2)
109+
cache.set(1, 1)
110+
cache.set(2, 2)
111+
112+
console.log(cache.get(1))
113+
114+
cache.set(3, 3)
115+
116+
console.log(cache.get(2)) // cache miss
117+
118+
cache.set(4, 4)
119+
120+
console.log(cache.get(1)) // cache miss
121+
console.log(cache.get(3))
122+
console.log(cache.get(4))
123+
124+
console.log('Example Cache: ', cache.cacheInfo(), '\n')
125+
126+
// Example 2 (Computing Fibonacci Series - 100 terms)
127+
function fib (num, cache = null) {
128+
if (cache) {
129+
const value = cache.get(num)
130+
if (value) { return value }
131+
}
132+
if (num === 1 || num === 2) { return 1 }
133+
const result = fib(num - 1, cache) + fib(num - 2, cache)
134+
if (cache) { cache.set(num, result) }
135+
return result
136+
}
137+
138+
const fibCache = new LFUCache(100)
139+
for (let i = 1; i <= 100; i++) { fib(i, fibCache) }
140+
console.log('Fibonacci Series Cache: ', fibCache.cacheInfo(), '\n')
141+
}
142+
143+
main()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /