Projects/LRUCache.py

173 lines
4.7 KiB
Python

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()