1+ class Node :
2+ # Create a building block for the cache
3+ def __init__ (self , key , value ):
4+ self .key = key
5+ self .value = value
6+ self .next = None
7+ self .previous = None
8+
9+
10+ class LruCache :
11+ # Initializes the cache with a maximum capacity
12+ def __init__ (self , limit ):
13+ if limit <= 0 :
14+ raise ValueError ("Cache limit must be greater than zero." )
15+ self .limit = limit
16+ self .cache = {} # Maps key -> Node for O(1) lookups
17+ self .head = None # Most recently used
18+ self .tail = None # Least recently used
19+
20+ # Looks up a value and marks it as recently used
21+ def get (self , key ):
22+ if key not in self .cache :
23+ return None
24+
25+ node = self .cache [key ]
26+ self ._move_to_head (node )
27+ return node .value
28+
29+ # Add or update an item, evicting the oldest if full
30+ def set (self , key , value ):
31+ if key in self .cache :
32+ node = self .cache [key ]
33+ node .value = value
34+ self ._move_to_head (node )
35+ return
36+
37+ if len (self .cache ) >= self .limit :
38+ if self .tail is not None :
39+ del self .cache [self .tail .key ]
40+
41+ if self .head == self .tail :
42+ self .head = None
43+ self .tail = None
44+ else :
45+ self .tail = self .tail .previous
46+ self .tail .next = None
47+
48+ new_node = Node (key , value )
49+ self .cache [key ] = new_node
50+
51+ if self .head is None :
52+ self .head = new_node
53+ self .tail = new_node
54+ else :
55+ new_node .next = self .head
56+ self .head .previous = new_node
57+ self .head = new_node
58+
59+ # Internal helper to reposition a used node to the front
60+ def _move_to_head (self , node ):
61+ if self .head == node :
62+ return
63+
64+ if node == self .tail :
65+ self .tail = node .previous
66+ self .tail .next = None
67+ else :
68+ node .previous .next = node .next
69+ node .next .previous = node .previous
70+
71+ node .next = self .head
72+ self .head .previous = node
73+ node .previous = None
74+ self .head = node
0 commit comments