From 6934c53c0400e1d3158014dfeb984e629c0bc8fb Mon Sep 17 00:00:00 2001 From: januslinhc Date: Fri, 29 Oct 2021 00:58:58 +0800 Subject: [PATCH] Add MRU Cache (#2738) --- DIRECTORY.md | 8 ++ DataStructures/Caches/MRUCache.java | 179 ++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 DataStructures/Caches/MRUCache.java diff --git a/DIRECTORY.md b/DIRECTORY.md index 4fd29a36..3a2ee7bd 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -3,6 +3,7 @@ * [IIRFilter](https://github.com/TheAlgorithms/Java/blob/master/AudioFilters/IIRFilter.java) ## Backtracking + * [KnightsTour](https://github.com/TheAlgorithms/Java/blob/master/Backtracking/KnightsTour.java) * [NQueens](https://github.com/TheAlgorithms/Java/blob/master/Backtracking/NQueens.java) * [PowerSum](https://github.com/TheAlgorithms/Java/blob/master/Backtracking/PowerSum.java) @@ -48,6 +49,7 @@ * [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) + * [MRUCache](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Caches/MRUCache.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) @@ -82,6 +84,7 @@ * Lists * [CircleLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CircleLinkedList.java) * [CountSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CountSinglyLinkedListRecursion.java) + * [CreateAndDetectLoop](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CreateAndDetectLoop.java) * [CursorLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CursorLinkedList.java) * [DoublyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/DoublyLinkedList.java) * [Merge K SortedLinkedlist](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/Merge_K_SortedLinkedlist.java) @@ -113,11 +116,14 @@ * [BSTRecursive](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/BSTRecursive.java) * [BSTRecursiveGeneric](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/BSTRecursiveGeneric.java) * [CeilInBinarySearchTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/CeilInBinarySearchTree.java) + * [CreateBinaryTreeFromInorderPreorder](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/CreateBinaryTreeFromInorderPreorder.java) + * [CreateBSTFromSortedArray](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/CreateBSTFromSortedArray.java) * [FenwickTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/FenwickTree.java) * [GenericTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/GenericTree.java) * [LCA](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LCA.java) * [LevelOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LevelOrderTraversal.java) * [LevelOrderTraversalQueue](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LevelOrderTraversalQueue.java) + * [nearestRightKey](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/nearestRightKey.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) @@ -253,6 +259,7 @@ ## Others * [BestFit](https://github.com/TheAlgorithms/Java/blob/master/Others/BestFit.java) * [BFPRT](https://github.com/TheAlgorithms/Java/blob/master/Others/BFPRT.java) + * [BoyerMoore](https://github.com/TheAlgorithms/Java/blob/master/Others/BoyerMoore.java) * [BrianKernighanAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/Others/BrianKernighanAlgorithm.java) * [CountChar](https://github.com/TheAlgorithms/Java/blob/master/Others/CountChar.java) * [CountWords](https://github.com/TheAlgorithms/Java/blob/master/Others/CountWords.java) @@ -317,6 +324,7 @@ * [SquareRootBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/SquareRootBinarySearch.java) * [TernarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/TernarySearch.java) * [UnionFind](https://github.com/TheAlgorithms/Java/blob/master/Searches/UnionFind.java) + * [UpperBound](https://github.com/TheAlgorithms/Java/blob/master/Searches/UpperBound.java) ## Sorts * [BitonicSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BitonicSort.java) diff --git a/DataStructures/Caches/MRUCache.java b/DataStructures/Caches/MRUCache.java new file mode 100644 index 00000000..e3156477 --- /dev/null +++ b/DataStructures/Caches/MRUCache.java @@ -0,0 +1,179 @@ +package DataStructures.Caches; + +import java.util.HashMap; +import java.util.Map; + +/** + * Most recently used (MRU) + *

+ * In contrast to Least Recently Used (LRU), MRU discards the most recently used items first. + * https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU) + * + * @param key type + * @param value type + */ +public class MRUCache { + private final Map> data = new HashMap<>(); + private Entry head; + private Entry tail; + private int cap; + private static final int DEFAULT_CAP = 100; + + public MRUCache() { + setCapacity(DEFAULT_CAP); + } + + private void setCapacity(int newCapacity) { + checkCapacity(newCapacity); + for (int i = data.size(); i > newCapacity; i--) { + Entry evicted = evict(); + data.remove(evicted.getKey()); + } + this.cap = newCapacity; + } + + + private void checkCapacity(int capacity) { + if (capacity <= 0) { + throw new RuntimeException("capacity must greater than 0!"); + } + } + + private Entry evict() { + if (head == null) { + throw new RuntimeException("cache cannot be empty!"); + } + final Entry evicted = this.tail; + tail = evicted.getPreEntry(); + tail.setNextEntry(null); + evicted.setNextEntry(null); + return evicted; + } + + public MRUCache(int cap) { + setCapacity(cap); + } + + public V get(K key) { + if (!data.containsKey(key)) { + return null; + } + final Entry entry = data.get(key); + moveEntryToLast(entry); + return entry.getValue(); + } + + public void put(K key, V value) { + if (data.containsKey(key)) { + final Entry exitingEntry = data.get(key); + exitingEntry.setValue(value); + moveEntryToLast(exitingEntry); + return; + } + Entry 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 newEntry) { + if (data.isEmpty()) { + head = newEntry; + tail = newEntry; + return; + } + tail.setNextEntry(newEntry); + newEntry.setPreEntry(tail); + newEntry.setNextEntry(null); + tail = newEntry; + } + + private void moveEntryToLast(Entry entry) { + if (tail == entry) { + return; + } + final Entry preEntry = entry.getPreEntry(); + final Entry 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; + } + + static final class Entry { + private Entry preEntry; + private Entry nextEntry; + private I key; + private J value; + + public Entry() { + } + + public Entry(Entry preEntry, Entry nextEntry, I key, J value) { + this.preEntry = preEntry; + this.nextEntry = nextEntry; + this.key = key; + this.value = value; + } + + public Entry getPreEntry() { + return preEntry; + } + + public void setPreEntry(Entry preEntry) { + this.preEntry = preEntry; + } + + public Entry getNextEntry() { + return nextEntry; + } + + public void setNextEntry(Entry 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 MRUCache cache = new MRUCache<>(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")); + } +}