Skip to content

Commit 769afdb

Browse files
Refactor LRU Cache to follow SRP - separate DoublyLinkedList class
1 parent 88a5d26 commit 769afdb

File tree

1 file changed

+62
-53
lines changed

1 file changed

+62
-53
lines changed
Lines changed: 62 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,41 @@
11
class Node:
2+
"""Represents a node in the doubly-linked list."""
23
def __init__(self, key, value):
34
self.key = key
45
self.value = value
56
self.next = None
67
self.previous = None
78

89

9-
class LruCache:
10-
def __init__(self, limit):
11-
if limit <= 0:
12-
raise ValueError("Cache limit must be greater than 0")
13-
14-
self.limit = limit
15-
self.cache = {}
16-
self.head = None
17-
self.tail = None
10+
class DoublyLinkedList:
11+
"""Manages insertion, removal, and reordering of nodes in a doubly-linked list."""
12+
def __init__(self):
13+
self.head = None
14+
self.tail = None
1815

19-
def get(self, key):
20-
if key not in self.cache:
21-
return None
22-
23-
node = self.cache[key]
24-
25-
self._move_to_head(node)
16+
def add_to_head(self, node):
17+
"""Add a node to the head of the list."""
18+
node.next = None
19+
node.previous = None
2620

27-
return node.value
28-
29-
def set(self, key, value):
30-
if key in self.cache:
31-
node = self.cache[key]
32-
node.value = value
33-
self._move_to_head(node)
21+
if self.head is None:
22+
self.head = node
23+
self.tail = node
3424
else:
35-
if len(self.cache) >= self.limit:
36-
self._evict_tail()
37-
38-
new_node = Node(key, value)
39-
self.cache[key] = new_node
40-
self._add_to_head(new_node)
25+
node.next = self.head
26+
self.head.previous = node
27+
self.head = node
4128

42-
def _move_to_head(self, node):
29+
def move_to_head(self, node):
30+
"""Move an existing node to the head of the list."""
4331
if node == self.head:
4432
return
4533

46-
self._remove_node(node)
47-
48-
self._add_to_head(node)
34+
self.remove_node(node)
35+
self.add_to_head(node)
4936

50-
def _remove_node(self, node):
37+
def remove_node(self, node):
38+
"""Remove a node from the list."""
5139
if node == self.head == self.tail:
5240
self.head = None
5341
self.tail = None
@@ -64,27 +52,48 @@ def _remove_node(self, node):
6452
node.next = None
6553
node.previous = None
6654

67-
def _add_to_head(self, node):
68-
node.next = None
69-
node.previous = None
55+
def get_tail(self):
56+
"""Return the tail node (least recently used)."""
57+
return self.tail
58+
59+
60+
class LruCache:
61+
"""Implements an LRU cache with O(1) operations."""
62+
def __init__(self, limit):
63+
if limit <= 0:
64+
raise ValueError("Cache limit must be greater than 0")
7065

71-
if self.head is None:
72-
self.head = node
73-
self.tail = node
74-
else:
75-
node.next = self.head
76-
self.head.previous = node
77-
self.head = node
66+
self.limit = limit
67+
self.cache = {}
68+
self.order = DoublyLinkedList()
7869

79-
def _evict_tail(self):
80-
if self.tail is None:
81-
return
70+
def get(self, key):
71+
"""Retrieve a value and mark it as recently used."""
72+
if key not in self.cache:
73+
return None
8274

83-
del self.cache[self.tail.key]
75+
node = self.cache[key]
76+
self.order.move_to_head(node)
8477

85-
if self.head == self.tail:
86-
self.head = None
87-
self.tail = None
78+
return node.value
79+
80+
def set(self, key, value):
81+
"""Store a key-value pair and evict LRU if necessary."""
82+
if key in self.cache:
83+
node = self.cache[key]
84+
node.value = value
85+
self.order.move_to_head(node)
8886
else:
89-
self.tail = self.tail.previous
90-
self.tail.next = None
87+
if len(self.cache) >= self.limit:
88+
self._evict_lru()
89+
90+
new_node = Node(key, value)
91+
self.cache[key] = new_node
92+
self.order.add_to_head(new_node)
93+
94+
def _evict_lru(self):
95+
"""Remove the least recently used item."""
96+
lru_node = self.order.get_tail()
97+
if lru_node is not None:
98+
del self.cache[lru_node.key]
99+
self.order.remove_node(lru_node)

0 commit comments

Comments
 (0)