4
4
import java .util .Map ;
5
5
6
6
/**
7
- * Least recently used (LRU)
8
- * <p>
9
- * Discards the least recently used items first. This algorithm requires keeping
10
- * track of what was used when, which is expensive if one wants to make sure the
11
- * algorithm always discards the least recently used item.
12
- * https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
7
+ * A Least Recently Used (LRU) Cache implementation.
13
8
*
14
- * @param <K> key type
15
- * @param <V> value type
9
+ * <p>An LRU cache is a fixed-size cache that maintains items in order of use. When the cache reaches
10
+ * its capacity and a new item needs to be added, it removes the least recently used item first.
11
+ * This implementation provides O(1) time complexity for both get and put operations.</p>
12
+ *
13
+ * <p>Features:</p>
14
+ * <ul>
15
+ * <li>Fixed-size cache with configurable capacity</li>
16
+ * <li>Constant time O(1) operations for get and put</li>
17
+ * <li>Thread-unsafe - should be externally synchronized if used in concurrent environments</li>
18
+ * <li>Supports null values but not null keys</li>
19
+ * </ul>
20
+ *
21
+ * <p>Implementation Details:</p>
22
+ * <ul>
23
+ * <li>Uses a HashMap for O(1) key-value lookups</li>
24
+ * <li>Maintains a doubly-linked list for tracking access order</li>
25
+ * <li>The head of the list contains the least recently used item</li>
26
+ * <li>The tail of the list contains the most recently used item</li>
27
+ * </ul>
28
+ *
29
+ * <p>Example usage:</p>
30
+ * <pre>
31
+ * LRUCache<String, Integer> cache = new LRUCache<>(3); // Create cache with capacity 3
32
+ * cache.put("A", 1); // Cache: A=1
33
+ * cache.put("B", 2); // Cache: A=1, B=2
34
+ * cache.put("C", 3); // Cache: A=1, B=2, C=3
35
+ * cache.get("A"); // Cache: B=2, C=3, A=1 (A moved to end)
36
+ * cache.put("D", 4); // Cache: C=3, A=1, D=4 (B evicted)
37
+ * </pre>
38
+ *
39
+ * @param <K> the type of keys maintained by this cache
40
+ * @param <V> the type of mapped values
16
41
*/
17
42
public class LRUCache <K , V > {
18
43
@@ -30,6 +55,11 @@ public LRUCache(int cap) {
30
55
setCapacity (cap );
31
56
}
32
57
58
+ /**
59
+ * Returns the current capacity of the cache.
60
+ *
61
+ * @param newCapacity the new capacity of the cache
62
+ */
33
63
private void setCapacity (int newCapacity ) {
34
64
checkCapacity (newCapacity );
35
65
for (int i = data .size (); i > newCapacity ; i --) {
@@ -39,6 +69,11 @@ private void setCapacity(int newCapacity) {
39
69
this .cap = newCapacity ;
40
70
}
41
71
72
+ /**
73
+ * Evicts the least recently used item from the cache.
74
+ *
75
+ * @return the evicted entry
76
+ */
42
77
private Entry <K , V > evict () {
43
78
if (head == null ) {
44
79
throw new RuntimeException ("cache cannot be empty!" );
@@ -50,12 +85,25 @@ private Entry<K, V> evict() {
50
85
return evicted ;
51
86
}
52
87
88
+ /**
89
+ * Checks if the capacity is valid.
90
+ *
91
+ * @param capacity the capacity to check
92
+ */
53
93
private void checkCapacity (int capacity ) {
54
94
if (capacity <= 0 ) {
55
95
throw new RuntimeException ("capacity must greater than 0!" );
56
96
}
57
97
}
58
98
99
+ /**
100
+ * Returns the value to which the specified key is mapped, or null if this cache contains no
101
+ * mapping for the key.
102
+ *
103
+ * @param key the key whose associated value is to be returned
104
+ * @return the value to which the specified key is mapped, or null if this cache contains no
105
+ * mapping for the key
106
+ */
59
107
public V get (K key ) {
60
108
if (!data .containsKey (key )) {
61
109
return null ;
@@ -65,6 +113,11 @@ public V get(K key) {
65
113
return entry .getValue ();
66
114
}
67
115
116
+ /**
117
+ * Moves the specified entry to the end of the list.
118
+ *
119
+ * @param entry the entry to move
120
+ */
68
121
private void moveNodeToLast (Entry <K , V > entry ) {
69
122
if (tail == entry ) {
70
123
return ;
@@ -86,6 +139,12 @@ private void moveNodeToLast(Entry<K, V> entry) {
86
139
tail = entry ;
87
140
}
88
141
142
+ /**
143
+ * Associates the specified value with the specified key in this cache.
144
+ *
145
+ * @param key the key with which the specified value is to be associated
146
+ * @param value the value to be associated with the specified key
147
+ */
89
148
public void put (K key , V value ) {
90
149
if (data .containsKey (key )) {
91
150
final Entry <K , V > existingEntry = data .get (key );
@@ -107,6 +166,11 @@ public void put(K key, V value) {
107
166
data .put (key , newEntry );
108
167
}
109
168
169
+ /**
170
+ * Adds a new entry to the end of the list.
171
+ *
172
+ * @param newEntry the entry to add
173
+ */
110
174
private void addNewEntry (Entry <K , V > newEntry ) {
111
175
if (data .isEmpty ()) {
112
176
head = newEntry ;
0 commit comments