diff --git a/src/main/java/com/thealgorithms/datastructures/caches/ARCCache.java b/src/main/java/com/thealgorithms/datastructures/caches/ARCCache.java
new file mode 100644
index 000000000000..5185f8583a57
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/caches/ARCCache.java
@@ -0,0 +1,132 @@
+package com.thealgorithms.datastructures.caches;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+/**
+ * Adaptive Replacement Cache (ARC)
+ *
+ * dynamically adjusts cache size based on recent access patterns.
+ * It aims to provide better performance compared to traditional caching algorithms
+ * like LRU (Least Recently Used) and LFU (Least Frequently Used).
+ * It combines elements of LRU (Least Recently Used) and LFU (Least Frequently Used) algorithms
+ * to efficiently manage frequently accessed and recently used items,
+ * optimizing cache performance in changing workload scenarios.
+ * ...
+ * @author Adarsh Pandey (...)
+ *
+ * @param key type
+ * @param value type
+ */
+
+public class ARCCache {
+ private final Map cache;
+ private final LinkedHashMap usageCounts;
+ private final int t1Capacity; // Capacity for the t1 cache
+ private final int b1Capacity; // Capacity for the b1 cache
+ private int totalCount;
+
+ /**
+ * This constructor initializes an ARCCache object with the given capacity and initializes other necessary fields
+ * @param capacity the initial capacity of the cache
+ * @throws IllegalArgumentException if the capacity is negative
+ */
+ public ARCCache(int capacity) {
+ if (capacity < 0) {
+ throw new IllegalArgumentException("Capacity cannot be negative");
+ }
+ this.cache = new LinkedHashMap<>();
+ this.usageCounts = new LinkedHashMap<>();
+ this.t1Capacity = capacity / 2; // Capacity for the t1 cache
+ this.b1Capacity = capacity - t1Capacity; // Capacity for the b1 cache
+ this.totalCount = 0;
+ }
+
+ /**
+ * Returns the total capacity of the cache
+ *
+ * @return the total capacity of the cache
+ */
+ private int capacity() {
+ return t1Capacity + b1Capacity;
+ }
+
+ /**
+ * Retrieves the value associated with the given key from the cache.
+ * If the key is present in the cache, its usage count is incremented.
+ *
+ * @param key the key whose associated value is to be retrieved
+ * @return the value associated with the key, or null if the key is not present in the cache
+ */
+ public V get(K key) {
+ if (cache.containsKey(key)) {
+ usageCounts.put(key, usageCounts.getOrDefault(key, 0) + 1);
+ return cache.get(key);
+ }
+ return null;
+ }
+
+ /**
+ * Adds the specified key-value pair to the cache.
+ * If the cache exceeds its capacity after adding the new entry, eviction is performed.
+ * Updates the usage count for the added key.
+ *
+ * @param key the key with which the specified value is to be associated
+ * @param value the value to be associated with the specified key
+ */
+ public void put(K key, V value) {
+ if (cache.size() >= capacity()) {
+ evict();
+ }
+ cache.put(key, value);
+ usageCounts.put(key, 1);
+ totalCount++;
+ }
+
+ /**
+ * Evicts an item from the cache when it exceeds its capacity.
+ * Implements the Adaptive Replacement Cache (ARC) algorithm logic for eviction.
+ * Removes the least recently used item based on its usage count.
+ */
+ private void evict() {
+ if (!cache.isEmpty()) {
+ K keyToRemove = null;
+ int minUsageCount = Integer.MAX_VALUE;
+ for (Map.Entry entry : usageCounts.entrySet()) {
+ if (entry.getValue() < minUsageCount) {
+ keyToRemove = entry.getKey();
+ minUsageCount = entry.getValue();
+ }
+ }
+ cache.remove(keyToRemove);
+ usageCounts.remove(keyToRemove);
+ totalCount--;
+ adjustCacheSize();
+ }
+ }
+
+ /**
+ * Adjust the cache sizes based on t1capacity and b1capacity after eviction from cache
+ */
+ private void adjustCacheSize() {
+ if (cache.size() > capacity()) {
+ int excess = cache.size() - capacity();
+ int t1Size = cache.size() - b1Capacity;
+ while (excess > 0 && !cache.isEmpty()) {
+ K keyToRemove = usageCounts.keySet().iterator().next();
+ if (t1Size > t1Capacity || (t1Size > 0 && usageCounts.get(keyToRemove) > 1)) {
+ cache.remove(keyToRemove);
+ usageCounts.remove(keyToRemove);
+ totalCount--;
+ if (t1Size > 0) {
+ t1Size--;
+ }
+ } else {
+ cache.remove(keyToRemove);
+ usageCounts.remove(keyToRemove);
+ totalCount--;
+ }
+ excess--;
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/caches/ARCCacheTest.java b/src/test/java/com/thealgorithms/datastructures/caches/ARCCacheTest.java
new file mode 100644
index 000000000000..79787125dbf7
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/caches/ARCCacheTest.java
@@ -0,0 +1,73 @@
+package com.thealgorithms.datastructures.caches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class ARCCacheTest {
+ private ARCCache cache;
+
+ @BeforeEach
+ public void setUp() {
+ int t1Capacity = 2;
+ int b1Capacity = 1;
+ int totalCapacity = t1Capacity + b1Capacity;
+ cache = new ARCCache<>(totalCapacity); // Set capacity to 3 for testing purposes
+ }
+
+ @Test
+ public void testPutAndGet() {
+ cache.put(1, "Value1");
+ cache.put(2, "Value2");
+ cache.put(3, "Value3");
+
+ assertEquals("Value1", cache.get(1));
+ assertEquals("Value2", cache.get(2));
+ assertEquals("Value3", cache.get(3));
+ }
+
+ @Test
+ public void testEviction() {
+ cache.put(1, "Value1");
+ cache.put(2, "Value2");
+ cache.put(3, "Value3");
+
+ cache.put(4, "Value4"); // This should evict key 1
+
+ assertNull(cache.get(1)); // Key 1 should have been evicted
+ assertEquals("Value2", cache.get(2)); // Other keys should still be present
+ assertEquals("Value3", cache.get(3));
+ assertEquals("Value4", cache.get(4));
+ }
+
+ @Test
+ public void nullKeysAndValues() {
+ cache.put(null, "Value1");
+ cache.put(2, null);
+
+ assertEquals("Value1", cache.get(null));
+ assertNull(cache.get(2));
+ assertNull(cache.get(6));
+ }
+
+ @Test
+ public void testRepeatedGet() {
+ cache.put(1, "Value1");
+
+ // Repeated get calls should not affect eviction
+ cache.get(1);
+ cache.get(1);
+ cache.get(1);
+
+ // Adding new elements should still evict old ones
+ cache.put(2, "Value2");
+ cache.put(3, "Value3");
+ cache.put(4, "Value4");
+
+ assertNull(cache.get(2)); // Key 2 should have been evicted
+ assertEquals("Value1", cache.get(1)); // Other keys should still be present
+ assertEquals("Value3", cache.get(3)); // Other keys should still be present
+ }
+}