mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-07 09:45:04 +08:00
Add LRU Cache (#2740)
This commit is contained in:
19
DIRECTORY.md
19
DIRECTORY.md
@ -1,5 +1,5 @@
|
||||
|
||||
## Audio Filters
|
||||
## AudioFilters
|
||||
* [IIRFilter](https://github.com/TheAlgorithms/Java/blob/master/AudioFilters/IIRFilter.java)
|
||||
|
||||
## Backtracking
|
||||
@ -46,11 +46,17 @@
|
||||
* [Bag](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Bags/Bag.java)
|
||||
* Buffers
|
||||
* [CircularBuffer](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Buffers/CircularBuffer.java)
|
||||
* Caches
|
||||
* [LRUCache](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Caches/LRUCache.java)
|
||||
* DisjointSets
|
||||
* [DisjointSets](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DisjointSets/DisjointSets.java)
|
||||
* [Node](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DisjointSets/Node.java)
|
||||
* DynamicArray
|
||||
* [DynamicArray](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DynamicArray/DynamicArray.java)
|
||||
* Graphs
|
||||
* [A Star](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/A_Star.java)
|
||||
* [BellmanFord](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/BellmanFord.java)
|
||||
* [BipartiteGrapfDFS](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/BipartiteGrapfDFS.java)
|
||||
* [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/ConnectedComponent.java)
|
||||
* [Cycles](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/Cycles.java)
|
||||
* [DIJSKSTRAS ALGORITHM](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/DIJSKSTRAS_ALGORITHM.java)
|
||||
@ -96,6 +102,7 @@
|
||||
* [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/InfixToPostfix.java)
|
||||
* [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/MaximumMinimumWindow.java)
|
||||
* [NodeStack](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/NodeStack.java)
|
||||
* [ReverseStack](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/ReverseStack.java)
|
||||
* [StackArray](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/StackArray.java)
|
||||
* [StackArrayList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/StackArrayList.java)
|
||||
* [StackOfLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/StackOfLinkedList.java)
|
||||
@ -113,6 +120,7 @@
|
||||
* [LevelOrderTraversalQueue](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LevelOrderTraversalQueue.java)
|
||||
* [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/PrintTopViewofTree.java)
|
||||
* [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/RedBlackBST.java)
|
||||
* [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/SegmentTree.java)
|
||||
* [TreeTraversal](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/TreeTraversal.java)
|
||||
* [TrieImp](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/TrieImp.java)
|
||||
* [ValidBSTOrNot](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/ValidBSTOrNot.java)
|
||||
@ -145,6 +153,7 @@
|
||||
* [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/LongestPalindromicSubstring.java)
|
||||
* [LongestValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/LongestValidParentheses.java)
|
||||
* [MatrixChainMultiplication](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MatrixChainMultiplication.java)
|
||||
* [MatrixChainRecursiveTopDownMemoisation](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MatrixChainRecursiveTopDownMemoisation.java)
|
||||
* [MemoizationTechniqueKnapsack](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MemoizationTechniqueKnapsack.java)
|
||||
* [MinimumPathSum](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MinimumPathSum.java)
|
||||
* [MinimumSumPartition](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MinimumSumPartition.java)
|
||||
@ -181,6 +190,7 @@
|
||||
* [FactorialRecursion](https://github.com/TheAlgorithms/Java/blob/master/Maths/FactorialRecursion.java)
|
||||
* [FFT](https://github.com/TheAlgorithms/Java/blob/master/Maths/FFT.java)
|
||||
* [FFTBluestein](https://github.com/TheAlgorithms/Java/blob/master/Maths/FFTBluestein.java)
|
||||
* [FibonacciJavaStreams](https://github.com/TheAlgorithms/Java/blob/master/Maths/FibonacciJavaStreams.java)
|
||||
* [FibonacciNumber](https://github.com/TheAlgorithms/Java/blob/master/Maths/FibonacciNumber.java)
|
||||
* [FindMax](https://github.com/TheAlgorithms/Java/blob/master/Maths/FindMax.java)
|
||||
* [FindMaxRecursion](https://github.com/TheAlgorithms/Java/blob/master/Maths/FindMaxRecursion.java)
|
||||
@ -216,8 +226,10 @@
|
||||
* [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/Maths/PrimeFactorization.java)
|
||||
* [PythagoreanTriple](https://github.com/TheAlgorithms/Java/blob/master/Maths/PythagoreanTriple.java)
|
||||
* [RomanNumeralUtil](https://github.com/TheAlgorithms/Java/blob/master/Maths/RomanNumeralUtil.java)
|
||||
* [SimpsonIntegration](https://github.com/TheAlgorithms/Java/blob/master/Maths/SimpsonIntegration.java)
|
||||
* [SumOfArithmeticSeries](https://github.com/TheAlgorithms/Java/blob/master/Maths/SumOfArithmeticSeries.java)
|
||||
* [SumOfDigits](https://github.com/TheAlgorithms/Java/blob/master/Maths/SumOfDigits.java)
|
||||
* [TrinomialTriangle](https://github.com/TheAlgorithms/Java/blob/master/Maths/TrinomialTriangle.java)
|
||||
* [VampireNumber](https://github.com/TheAlgorithms/Java/blob/master/Maths/VampireNumber.java)
|
||||
* [VectorCrossProduct](https://github.com/TheAlgorithms/Java/blob/master/Maths/VectorCrossProduct.java)
|
||||
|
||||
@ -234,6 +246,7 @@
|
||||
* [MedianOfRunningArray](https://github.com/TheAlgorithms/Java/blob/master/Misc/MedianOfRunningArray.java)
|
||||
* [PalindromePrime](https://github.com/TheAlgorithms/Java/blob/master/Misc/PalindromePrime.java)
|
||||
* [RangeInSortedArray](https://github.com/TheAlgorithms/Java/blob/master/Misc/RangeInSortedArray.java)
|
||||
* [Sparcity](https://github.com/TheAlgorithms/Java/blob/master/Misc/Sparcity.java)
|
||||
* [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/Misc/TwoSumProblem.java)
|
||||
* [WordBoggle](https://github.com/TheAlgorithms/Java/blob/master/Misc/WordBoggle.java)
|
||||
|
||||
@ -289,6 +302,7 @@
|
||||
## Searches
|
||||
* [BinarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/BinarySearch.java)
|
||||
* [ExponentalSearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/ExponentalSearch.java)
|
||||
* [FibonacciSearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/FibonacciSearch.java)
|
||||
* [HowManyTimesRotated](https://github.com/TheAlgorithms/Java/blob/master/Searches/HowManyTimesRotated.java)
|
||||
* [InterpolationSearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/InterpolationSearch.java)
|
||||
* [IterativeBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/IterativeBinarySearch.java)
|
||||
@ -310,6 +324,7 @@
|
||||
* [BubbleSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BubbleSort.java)
|
||||
* [BubbleSortRecursion](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BubbleSortRecursion.java)
|
||||
* [BucketSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BucketSort.java)
|
||||
* [CircleSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CircleSort.java)
|
||||
* [CocktailShakerSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CocktailShakerSort.java)
|
||||
* [CombSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CombSort.java)
|
||||
* [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CountingSort.java)
|
||||
@ -319,6 +334,7 @@
|
||||
* [HeapSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/HeapSort.java)
|
||||
* [InsertionSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/InsertionSort.java)
|
||||
* [MergeSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/MergeSort.java)
|
||||
* [MergeSortNoExtraSpace](https://github.com/TheAlgorithms/Java/blob/master/Sorts/MergeSortNoExtraSpace.java)
|
||||
* [MergeSortRecursive](https://github.com/TheAlgorithms/Java/blob/master/Sorts/MergeSortRecursive.java)
|
||||
* [PancakeSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/PancakeSort.java)
|
||||
* [QuickSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/QuickSort.java)
|
||||
@ -345,6 +361,7 @@
|
||||
* [Lower](https://github.com/TheAlgorithms/Java/blob/master/Strings/Lower.java)
|
||||
* [Palindrome](https://github.com/TheAlgorithms/Java/blob/master/Strings/Palindrome.java)
|
||||
* [Pangram](https://github.com/TheAlgorithms/Java/blob/master/Strings/Pangram.java)
|
||||
* [PermuteString](https://github.com/TheAlgorithms/Java/blob/master/Strings/PermuteString.java)
|
||||
* [ReverseString](https://github.com/TheAlgorithms/Java/blob/master/Strings/ReverseString.java)
|
||||
* [Rotation](https://github.com/TheAlgorithms/Java/blob/master/Strings/Rotation.java)
|
||||
* [Upper](https://github.com/TheAlgorithms/Java/blob/master/Strings/Upper.java)
|
||||
|
182
DataStructures/Caches/LRUCache.java
Normal file
182
DataStructures/Caches/LRUCache.java
Normal file
@ -0,0 +1,182 @@
|
||||
package DataStructures.Caches;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Least recently used (LRU)
|
||||
* <p>
|
||||
* Discards the least recently used items first.
|
||||
* This algorithm requires keeping track of what was used when,
|
||||
* which is expensive if one wants to make sure the algorithm always discards
|
||||
* the least recently used item.
|
||||
* https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
|
||||
*
|
||||
* @param <K> key type
|
||||
* @param <V> value type
|
||||
*/
|
||||
public class LRUCache<K, V> {
|
||||
private final Map<K, Entry<K, V>> data = new HashMap<>();
|
||||
private Entry<K, V> head;
|
||||
private Entry<K, V> tail;
|
||||
private int cap;
|
||||
private static final int DEFAULT_CAP = 100;
|
||||
|
||||
public LRUCache() {
|
||||
setCapacity(DEFAULT_CAP);
|
||||
}
|
||||
|
||||
public LRUCache(int cap) {
|
||||
setCapacity(cap);
|
||||
}
|
||||
|
||||
private void setCapacity(int newCapacity) {
|
||||
checkCapacity(newCapacity);
|
||||
for (int i = data.size(); i > newCapacity; i--) {
|
||||
Entry<K, V> evicted = evict();
|
||||
data.remove(evicted.getKey());
|
||||
}
|
||||
this.cap = newCapacity;
|
||||
}
|
||||
|
||||
private Entry<K, V> evict() {
|
||||
if (head == null) {
|
||||
throw new RuntimeException("cache cannot be empty!");
|
||||
}
|
||||
Entry<K, V> evicted = head;
|
||||
head = evicted.getNextEntry();
|
||||
head.setPreEntry(null);
|
||||
evicted.setNextEntry(null);
|
||||
return evicted;
|
||||
}
|
||||
|
||||
private void checkCapacity(int capacity) {
|
||||
if (capacity <= 0) {
|
||||
throw new RuntimeException("capacity must greater than 0!");
|
||||
}
|
||||
}
|
||||
|
||||
public V get(K key) {
|
||||
if (!data.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
final Entry<K, V> entry = data.get(key);
|
||||
moveNodeToLast(entry);
|
||||
return entry.getValue();
|
||||
}
|
||||
|
||||
private void moveNodeToLast(Entry<K, V> entry) {
|
||||
if (tail == entry) {
|
||||
return;
|
||||
}
|
||||
final Entry<K, V> preEntry = entry.getPreEntry();
|
||||
final Entry<K, V> nextEntry = entry.getNextEntry();
|
||||
if (preEntry != null) {
|
||||
preEntry.setNextEntry(nextEntry);
|
||||
}
|
||||
if (nextEntry != null) {
|
||||
nextEntry.setPreEntry(preEntry);
|
||||
}
|
||||
if (head == entry) {
|
||||
head = nextEntry;
|
||||
}
|
||||
tail.setNextEntry(entry);
|
||||
entry.setPreEntry(tail);
|
||||
entry.setNextEntry(null);
|
||||
tail = entry;
|
||||
}
|
||||
|
||||
public void put(K key, V value) {
|
||||
if (data.containsKey(key)) {
|
||||
final Entry<K, V> existingEntry = data.get(key);
|
||||
existingEntry.setValue(value);
|
||||
moveNodeToLast(existingEntry);
|
||||
return;
|
||||
}
|
||||
Entry<K, V> newEntry;
|
||||
if (data.size() == cap) {
|
||||
newEntry = evict();
|
||||
data.remove(newEntry.getKey());
|
||||
} else {
|
||||
newEntry = new Entry<>();
|
||||
}
|
||||
|
||||
newEntry.setKey(key);
|
||||
newEntry.setValue(value);
|
||||
addNewEntry(newEntry);
|
||||
data.put(key, newEntry);
|
||||
}
|
||||
|
||||
private void addNewEntry(Entry<K, V> newEntry) {
|
||||
if (data.isEmpty()) {
|
||||
head = newEntry;
|
||||
tail = newEntry;
|
||||
return;
|
||||
}
|
||||
tail.setNextEntry(newEntry);
|
||||
newEntry.setPreEntry(tail);
|
||||
newEntry.setNextEntry(null);
|
||||
tail = newEntry;
|
||||
}
|
||||
|
||||
static final class Entry<I, J> {
|
||||
private Entry<I, J> preEntry;
|
||||
private Entry<I, J> nextEntry;
|
||||
private I key;
|
||||
private J value;
|
||||
|
||||
public Entry() {
|
||||
}
|
||||
|
||||
public Entry(Entry<I, J> preEntry, Entry<I, J> nextEntry, I key, J value) {
|
||||
this.preEntry = preEntry;
|
||||
this.nextEntry = nextEntry;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Entry<I, J> getPreEntry() {
|
||||
return preEntry;
|
||||
}
|
||||
|
||||
public void setPreEntry(Entry<I, J> preEntry) {
|
||||
this.preEntry = preEntry;
|
||||
}
|
||||
|
||||
public Entry<I, J> getNextEntry() {
|
||||
return nextEntry;
|
||||
}
|
||||
|
||||
public void setNextEntry(Entry<I, J> nextEntry) {
|
||||
this.nextEntry = nextEntry;
|
||||
}
|
||||
|
||||
public I getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(I key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public J getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(J value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final LRUCache<String, Integer> cache = new LRUCache<>(2);
|
||||
cache.put("Key1", 1);
|
||||
cache.put("Key2", 2);
|
||||
cache.put("Key3", 3);
|
||||
cache.put("Key4", 4);
|
||||
System.out.println("getValue(Key1): " + cache.get("Key1"));
|
||||
System.out.println("getValue(Key2): " + cache.get("Key2"));
|
||||
System.out.println("getValue(Key3): " + cache.get("Key3"));
|
||||
System.out.println("getValue(Key4): " + cache.get("Key4"));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user