Skip to content

Commit 0724f4f

Browse files
authored
Merge branch 'master' into lru_improve
2 parents 76e9311 + 520e464 commit 0724f4f

File tree

6 files changed

+381
-47
lines changed

6 files changed

+381
-47
lines changed

src/main/java/com/thealgorithms/datastructures/caches/MRUCache.java

Lines changed: 79 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
import java.util.Map;
55

66
/**
7-
* Most recently used (MRU)
7+
* Represents a Most Recently Used (MRU) Cache.
88
* <p>
9-
* In contrast to Least Recently Used (LRU), MRU discards the most recently used
10-
* items first.
11-
* https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)
9+
* In contrast to the Least Recently Used (LRU) strategy, the MRU caching policy
10+
* evicts the most recently accessed items first. This class provides methods to
11+
* store key-value pairs and manage cache eviction based on this policy.
1212
*
13-
* @param <K> key type
14-
* @param <V> value type
13+
* For more information, refer to:
14+
* <a href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)">MRU on Wikipedia</a>.
15+
*
16+
* @param <K> the type of keys maintained by this cache
17+
* @param <V> the type of values associated with the keys
1518
*/
1619
public class MRUCache<K, V> {
1720

@@ -21,40 +24,74 @@ public class MRUCache<K, V> {
2124
private int cap;
2225
private static final int DEFAULT_CAP = 100;
2326

27+
/**
28+
* Creates an MRUCache with the default capacity.
29+
*/
2430
public MRUCache() {
2531
setCapacity(DEFAULT_CAP);
2632
}
2733

34+
/**
35+
* Creates an MRUCache with a specified capacity.
36+
*
37+
* @param cap the maximum number of items the cache can hold
38+
*/
39+
public MRUCache(int cap) {
40+
setCapacity(cap);
41+
}
42+
43+
/**
44+
* Sets the capacity of the cache and evicts items if the new capacity
45+
* is less than the current number of items.
46+
*
47+
* @param newCapacity the new capacity to set
48+
*/
2849
private void setCapacity(int newCapacity) {
2950
checkCapacity(newCapacity);
30-
for (int i = data.size(); i > newCapacity; i--) {
51+
while (data.size() > newCapacity) {
3152
Entry<K, V> evicted = evict();
3253
data.remove(evicted.getKey());
3354
}
3455
this.cap = newCapacity;
3556
}
3657

58+
/**
59+
* Checks if the specified capacity is valid.
60+
*
61+
* @param capacity the capacity to check
62+
* @throws IllegalArgumentException if the capacity is less than or equal to zero
63+
*/
3764
private void checkCapacity(int capacity) {
3865
if (capacity <= 0) {
39-
throw new RuntimeException("capacity must greater than 0!");
66+
throw new IllegalArgumentException("Capacity must be greater than 0!");
4067
}
4168
}
4269

70+
/**
71+
* Evicts the most recently used entry from the cache.
72+
*
73+
* @return the evicted entry
74+
* @throws RuntimeException if the cache is empty
75+
*/
4376
private Entry<K, V> evict() {
4477
if (head == null) {
45-
throw new RuntimeException("cache cannot be empty!");
78+
throw new RuntimeException("Cache cannot be empty!");
4679
}
4780
final Entry<K, V> evicted = this.tail;
4881
tail = evicted.getPreEntry();
49-
tail.setNextEntry(null);
82+
if (tail != null) {
83+
tail.setNextEntry(null);
84+
}
5085
evicted.setNextEntry(null);
5186
return evicted;
5287
}
5388

54-
public MRUCache(int cap) {
55-
setCapacity(cap);
56-
}
57-
89+
/**
90+
* Retrieves the value associated with the specified key.
91+
*
92+
* @param key the key whose associated value is to be returned
93+
* @return the value associated with the specified key, or null if the key does not exist
94+
*/
5895
public V get(K key) {
5996
if (!data.containsKey(key)) {
6097
return null;
@@ -64,11 +101,19 @@ public V get(K key) {
64101
return entry.getValue();
65102
}
66103

104+
/**
105+
* Associates the specified value with the specified key in the cache.
106+
* If the key already exists, its value is updated and the entry is moved to the most recently used position.
107+
* If the cache is full, the most recently used entry is evicted before adding the new entry.
108+
*
109+
* @param key the key with which the specified value is to be associated
110+
* @param value the value to be associated with the specified key
111+
*/
67112
public void put(K key, V value) {
68113
if (data.containsKey(key)) {
69-
final Entry<K, V> exitingEntry = data.get(key);
70-
exitingEntry.setValue(value);
71-
moveEntryToLast(exitingEntry);
114+
final Entry<K, V> existingEntry = data.get(key);
115+
existingEntry.setValue(value);
116+
moveEntryToLast(existingEntry);
72117
return;
73118
}
74119
Entry<K, V> newEntry;
@@ -84,6 +129,11 @@ public void put(K key, V value) {
84129
data.put(key, newEntry);
85130
}
86131

132+
/**
133+
* Adds a new entry to the cache and updates the head and tail pointers accordingly.
134+
*
135+
* @param newEntry the new entry to be added
136+
*/
87137
private void addNewEntry(Entry<K, V> newEntry) {
88138
if (data.isEmpty()) {
89139
head = newEntry;
@@ -96,6 +146,11 @@ private void addNewEntry(Entry<K, V> newEntry) {
96146
tail = newEntry;
97147
}
98148

149+
/**
150+
* Moves the specified entry to the most recently used position in the cache.
151+
*
152+
* @param entry the entry to be moved
153+
*/
99154
private void moveEntryToLast(Entry<K, V> entry) {
100155
if (tail == entry) {
101156
return;
@@ -117,8 +172,14 @@ private void moveEntryToLast(Entry<K, V> entry) {
117172
tail = entry;
118173
}
119174

175+
/**
176+
* A nested class representing an entry in the cache, which holds a key-value pair
177+
* and references to the previous and next entries in the linked list structure.
178+
*
179+
* @param <I> the type of the key
180+
* @param <J> the type of the value
181+
*/
120182
static final class Entry<I, J> {
121-
122183
private Entry<I, J> preEntry;
123184
private Entry<I, J> nextEntry;
124185
private I key;

0 commit comments

Comments
 (0)