|
1 | 1 | class Node: |
| 2 | + """Represents a single node in the doubly linked list.""" |
2 | 3 | def __init__(self, key, value): |
3 | 4 | self.key = key |
4 | 5 | self.value = value |
5 | 6 | self.prev = None |
6 | 7 | self.next = None |
7 | 8 |
|
8 | 9 |
|
9 | | -class LruCache: |
10 | | - def __init__(self, limit): |
11 | | - if limit <= 0: |
12 | | - raise ValueError("Capacity must be greater than 0") |
13 | | - self.capacity = limit |
14 | | - self.cache = {} |
15 | | - |
| 10 | +class DoublyLinkedList: |
| 11 | + """Manages a doubly linked list with sentinel head and tail nodes.""" |
| 12 | + |
| 13 | + def __init__(self): |
16 | 14 | self.head = Node(None, None) |
17 | 15 | self.tail = Node(None, None) |
18 | | - |
19 | 16 | self.head.next = self.tail |
20 | 17 | self.tail.prev = self.head |
21 | 18 |
|
22 | | - def _remove(self, node): |
| 19 | + def add_to_front(self, node): |
| 20 | + """Add a node to the front of the list (right after head).""" |
| 21 | + node.prev = self.head |
| 22 | + node.next = self.head.next |
| 23 | + self.head.next.prev = node |
| 24 | + self.head.next = node |
| 25 | + |
| 26 | + def remove(self, node): |
| 27 | + """Remove a node from the list.""" |
23 | 28 | prev_node = node.prev |
24 | 29 | next_node = node.next |
25 | 30 | prev_node.next = next_node |
26 | 31 | next_node.prev = prev_node |
27 | 32 |
|
28 | | - def _add_to_front(self, node): |
29 | | - node.prev = self.head |
30 | | - node.next = self.head.next |
31 | | - self.head.next.prev = node |
32 | | - self.head.next = node |
| 33 | + def get_least_recent(self): |
| 34 | + """Get the least recently used node (just before tail).""" |
| 35 | + return self.tail.prev |
| 36 | + |
| 37 | + |
| 38 | +class LruCache: |
| 39 | + """LRU Cache implementation using a doubly linked list to track usage order.""" |
| 40 | + |
| 41 | + def __init__(self, limit): |
| 42 | + if limit <= 0: |
| 43 | + raise ValueError("Capacity must be greater than 0") |
| 44 | + self.capacity = limit |
| 45 | + self.cache = {} |
| 46 | + self.linked_list = DoublyLinkedList() |
33 | 47 |
|
34 | 48 | def get(self, key): |
| 49 | + """Get a value from the cache and mark it as recently used.""" |
35 | 50 | if key not in self.cache: |
36 | 51 | return None |
37 | 52 |
|
38 | 53 | node = self.cache[key] |
39 | | - self._remove(node) |
40 | | - self._add_to_front(node) |
| 54 | + self.linked_list.remove(node) |
| 55 | + self.linked_list.add_to_front(node) |
41 | 56 | return node.value |
42 | 57 |
|
43 | 58 | def set(self, key, value): |
| 59 | + """Set a value in the cache, evicting the LRU item if at capacity.""" |
44 | 60 | if key in self.cache: |
45 | 61 | node = self.cache[key] |
46 | 62 | node.value = value |
47 | | - self._remove(node) |
48 | | - self._add_to_front(node) |
| 63 | + self.linked_list.remove(node) |
| 64 | + self.linked_list.add_to_front(node) |
49 | 65 | else: |
50 | 66 | new_node = Node(key, value) |
51 | 67 | self.cache[key] = new_node |
52 | | - self._add_to_front(new_node) |
| 68 | + self.linked_list.add_to_front(new_node) |
53 | 69 |
|
54 | 70 | if len(self.cache) > self.capacity: |
55 | | - lru = self.tail.prev |
56 | | - self._remove(lru) |
| 71 | + lru = self.linked_list.get_least_recent() |
| 72 | + self.linked_list.remove(lru) |
57 | 73 | del self.cache[lru.key] |
0 commit comments