1+ package com .caching ;
2+
3+ import java .util .HashMap ;
4+ import java .util .NoSuchElementException ;
5+ import java .util .TreeMap ;
6+
7+ /**
8+ * Your LFUCache object can be instantiated and called as such: LFUCache
9+ * lfuCache = new LFUCache(capacity); lfuCache.put(key,value); int param_1 =
10+ * lfuCache.get(key);
11+ */
12+ class LFUCache <T > {
13+ // internal Node to store cache element
14+ private class Node {
15+ int key ;
16+ T value ;
17+ int freq ;
18+ Node next ;
19+ Node pre ;
20+
21+ public Node (int key , T value , int freq ) {
22+ this .key = key ;
23+ this .value = value ;
24+ this .freq = freq ;
25+ next = pre = null ;
26+ }
27+
28+ public String toString () {
29+ return " Key: " + key + "Value: " + value + "Freq: " + freq ;
30+ }
31+
32+ }
33+
34+ // internal Doubly Linked List to store cache nodes
35+ private class DLL {
36+ Node head ;
37+ Node tail ;
38+ int len ;
39+
40+ public DLL () {
41+ head = new Node (-1 , null , -1 );
42+ tail = new Node (-1 , null , -1 );
43+ head .next = tail ;
44+ tail .pre = head ;
45+ len = 0 ;
46+ }
47+
48+ public void addToHead (Node node ) {
49+ node .next = head .next ;
50+ head .next .pre = node ;
51+ head .next = node ;
52+ node .pre = head ;
53+ len ++;
54+ }
55+
56+ public void deleteNode (Node node ) {
57+ node .pre .next = node .next ;
58+ node .next .pre = node .pre ;
59+ len --;
60+ }
61+
62+ }
63+
64+ private int capacity ;
65+ private int size ;
66+ private TreeMap <Integer , DLL > freq ;
67+ private HashMap <Integer , Node > map ;
68+
69+ /**
70+ * instantiates LFUCache with fixed capacity
71+ *
72+ * @param capacity The capacity of the cache. Once the cache reaches capacity,
73+ * new elements will replace old elements in LFU manner
74+ */
75+ public LFUCache (int capacity ) {
76+ this .capacity = capacity ;
77+ size = 0 ;
78+ freq = new TreeMap <Integer , DLL >();
79+ map = new HashMap <Integer , Node >();
80+ System .out .println ("LFUCache initialised with capacity: " + capacity );
81+ }
82+
83+ /**
84+ * To get the cached value for given key
85+ *
86+ * @param key The key (int) of the expected value
87+ * @return corresponding value for input key
88+ * @throws NoSuchElementException if key is absent
89+ */
90+ public T get (int key ) {
91+ // Cache hit condition
92+ if (map .containsKey (key )) {
93+ Node node = map .get (key );
94+ System .out .println ("Returning value from cache:" + node .toString ());
95+ DLL dll = freq .get (node .freq );
96+ dll .deleteNode (node );
97+ if (dll .len == 0 )
98+ freq .remove (node .freq );
99+ node .freq += 1 ;
100+ dll = freq .computeIfAbsent (node .freq , k -> new DLL ());
101+ dll .addToHead (node );
102+ return node .value ;
103+ }
104+ // Cache miss condition
105+ throw new NoSuchElementException ("No element for key: " + key );
106+ }
107+
108+ /**
109+ * To put a value in LFU cache with corresponding key
110+ *
111+ * @param key The key (int)
112+ * @param value The value to be cached
113+ */
114+ public void put (int key , T value ) {
115+ if (capacity == 0 ) {
116+ System .out .println ("Cache set to 0 capacity. No element will be cached" );
117+ return ;
118+ }
119+ if (map .containsKey (key )) {
120+ System .out .println ("Key " + key + " already present in cache.Value will be replaced" );
121+ Node node = map .get (key );
122+ node .value = value ;
123+ DLL dll = freq .get (node .freq );
124+ dll .deleteNode (node );
125+ if (dll .len == 0 )
126+ freq .remove (node .freq );
127+ node .freq += 1 ;
128+ dll = freq .computeIfAbsent (node .freq , k -> new DLL ());
129+ dll .addToHead (node );
130+ } else {
131+ System .out .println ("Adding new key " + key + " to cache" );
132+ Node node = new Node (key , value , 1 );
133+ map .put (key , node );
134+
135+ if (size < capacity ) {
136+ size ++;
137+ DLL dll = freq .computeIfAbsent (1 , k -> new DLL ());
138+ dll .addToHead (node );
139+ } else {
140+ System .out .println ("Cache at peak capacity.Old values will be removed in LFU fashion" );
141+ Integer lowest = freq .firstKey ();
142+ DLL dll = freq .get (lowest );
143+ map .remove (dll .tail .pre .key );
144+ System .out .println ("Value removed:" + dll .tail .pre .value .toString ());
145+ dll .deleteNode (dll .tail .pre );
146+ if (dll .len == 0 && lowest != 1 )
147+ freq .remove (lowest );
148+ DLL freq_one = freq .computeIfAbsent (1 , k -> new DLL ());
149+ freq_one .addToHead (node );
150+ }
151+ }
152+
153+ }
154+
155+ }
0 commit comments