import json from datetime import datetime import os class Node: def __init__(self, key, value): self.key = key self.value = value self.prev = None self.next = None class LRUCache: def __init__(self, capacity): self.capacity = capacity self.cache = {} # key → Node self.head = None self.tail = None def _remove(self, node): if node.prev: node.prev.next = node.next else: self.head = node.next # node was head if node.next: node.next.prev = node.prev else: self.tail = node.prev # node was tail def _add_to_front(self, node): node.next = self.head node.prev = None if self.head: self.head.prev = node self.head = node if not self.tail: self.tail = node def get(self, key): if key not in self.cache: return -1 node = self.cache[key] self._remove(node) self._add_to_front(node) return node.value def put(self, key, value): if key in self.cache: self._remove(self.cache[key]) elif len(self.cache) >= self.capacity: del self.cache[self.tail.key] self._remove(self.tail) new_node = Node(key, value) self._add_to_front(new_node) self.cache[key] = new_node def display(self): current = self.head print("Cache (MRU → LRU): ", end="") while current: print(f"[{current.key}: {current.value}]", end=" ⇄ ") current = current.next print("None") def display_reverse(self): current = self.tail print("Cache (LRU → MRU): ", end="") while current: print(f"[{current.key}: {current.value}]", end=" ⇄ ") current = current.prev print("None") def to_dict(self): result = {} current = self.head while current: result[current.key] = current.value current = current.next return result def from_dict(self, data_dict): self.cache.clear() self.head = None self.tail = None for key, value in data_dict.items(): if len(self.cache) >= self.capacity: break # Respect capacity limit new_node = Node(key, value) self._add_to_front(new_node) self.cache[key] = new_node def save_to_file(self, filename=None, version="1.0"): timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") if not filename: filename = f"cache_{timestamp}.json" data = { "version": version, "timestamp": datetime.now().isoformat(), "cache": self.to_dict() } with open(filename, 'w') as f: json.dump(data, f, indent=2) print(f"Cache saved to {filename}") def load_from_file(self, filename): try: with open(filename, 'r') as f: data = json.load(f) version = data.get("version", "unknown") timestamp = data.get("timestamp", "unknown") print(f"Loaded cache version {version} from {timestamp}") self.from_dict(data.get("cache", {})) except (FileNotFoundError, json.JSONDecodeError) as e: print(f"Failed to load cache: {e}") def load_latest_cache(self, directory=".", prefix="cache_", extension=".json"): files = [ f for f in os.listdir(directory) if f.startswith(prefix) and f.endswith(extension) ] if not files: print("No saved cache files found.") return latest_file = max(files) # Lexicographic sort works with timestamped names print(f"Loading latest cache: {latest_file}") self.load_from_file(os.path.join(directory, latest_file)) @staticmethod def list_saved_caches(directory=".", prefix="cache_", extension=".json"): files = [] for filename in os.listdir(directory): if filename.startswith(prefix) and filename.endswith(extension): files.append(filename) files.sort() # Sort by name (timestamped) print("Saved cache files:") for f in files: print(" •", f) return files lru = LRUCache(3) lru.put("A", 1) lru.put("B", 2) lru.put("C", 3) lru.save_to_file("cache.json") # Later or in another session new_lru = LRUCache(3) new_lru.load_from_file("cache.json") new_lru.display() lru = LRUCache(4) lru.put("A", 1) lru.put("B", 2) lru.put("C", 3) lru.put("D", 4) lru.save_to_file() # Automatically names file like cache_2025-09-27_09-09-00.json list_saved_caches() lru = LRUCache(3) lru.load_latest_cache() lru.display()