Skip to content

Commit 1e8d10d

Browse files
committed
Refactor LRU Cache implementation to improve structure using LinkedList
1 parent 67c9cde commit 1e8d10d

1 file changed

Lines changed: 80 additions & 84 deletions

File tree

Lines changed: 80 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,91 @@
1-
'''
2-
if an item needs to be evicted, the item which was least recently used will be evicted.
3-
Both setting or getting a value counts as a use.
4-
It should support the following operations. Each operation should have a O(1) worst-case time complexity.
5-
* `LruCache(limit)` should construct an LRU cache which never stores more than `limit` entries.
6-
* `set(key, value)` should associate `value` with the passed `key`.
7-
* `get(key)` should look-up the value previously associated with `key`.
8-
'''
91

102
class Node:
113
def __init__(self, key, value):
12-
self.key = key # store the key
13-
self.value = value # store the value
14-
self.prev = None # previous node in list
15-
self.next = None # next node in list
16-
4+
self.key = key
5+
self.value = value
6+
self.previous = None
7+
self.next = None
8+
class LinkedList:
9+
def __init__(self):
10+
self.head = None
11+
self.tail = None
12+
13+
# adding a new value in the front of the list
14+
def push_head(self, node):
15+
node.previous = None
16+
node.next = self.head
17+
18+
if self.head is None: # if list is empty head and tail becomes this node.
19+
self.head = node
20+
self.tail = node
21+
else:
22+
self.head.previous = node
23+
self.head = node
24+
25+
return node # returns the node so we can remove it later
26+
27+
# removing last element
28+
def pop_tail(self):
29+
if self.tail is None:
30+
raise Exception("List is empty")
31+
32+
removed = self.tail
33+
self.remove(removed)
34+
return removed
35+
36+
# removes a specific node
37+
def remove(self, node):
38+
39+
if node.previous is None: # if removing head
40+
self.head = node.next
41+
else:
42+
node.previous.next = node.next # connect previous to next
43+
44+
if node.next is None: # if removing tail
45+
self.tail = node.previous
46+
else:
47+
node.next.previous = node.previous # connect next to previous
48+
# unplugging node
49+
node.next = None
50+
node.previous = None
1751

1852
class LruCache:
19-
def __init__(self, limit):
20-
53+
def __init__(self,limit) -> None:
54+
if limit <= 0:
55+
raise ValueError("Limit must be greater than zero")
2156
self.limit = limit
22-
self.data = {}
23-
self.first = None
24-
self.last = None
25-
26-
def set(self, key, value):
27-
28-
if key in self.data:
29-
node = self.data[key]
30-
node.value = value
31-
32-
# when node is used, is move to front
33-
if node != self.first:
3457

35-
if node.prev:
36-
node.prev.next = node.next
37-
if node.next:
38-
node.next.prev = node.prev
39-
40-
if node == self.last:
41-
self.last = node.prev
42-
43-
node.prev = None
44-
node.next = self.first
45-
self.first.prev = node
46-
self.first = node
58+
self.storage = {}
59+
self.order = LinkedList()
60+
pass
4761

62+
#If key already exists move it to MRU
63+
def touch (self,node):
64+
self.order.remove(node)
65+
self.order.push_head(node)
66+
67+
# If we want to add or update a key value pair
68+
def set(self, key, value):
69+
if key in self.storage:
70+
node = self.storage[key] #update the value of the key
71+
node.value = value
72+
self.touch(node)
4873
return
49-
50-
# create new node when key doesn't exit
51-
node = Node(key, value)
52-
self.data[key] = node
53-
54-
node.next = self.first
55-
if self.first:
56-
self.first.prev = node
57-
self.first = node
58-
59-
if self.last is None:
60-
self.last = node
61-
62-
# remove last when size is bigger than limit
63-
if len(self.data) > self.limit:
64-
old = self.last
65-
66-
del self.data[old.key]
67-
68-
self.last = old.prev
69-
if self.last:
70-
self.last.next = None
71-
72-
def get(self, key):
73-
74-
if key not in self.data:
74+
75+
#if we are adding a new key and at our limit
76+
if len(self.storage) >= self.limit:
77+
lru_node =self.order.pop_tail()
78+
del self.storage[lru_node.key]
79+
80+
#insert a new node
81+
new_node = Node(key, value)
82+
self.order.push_head(new_node)
83+
self.storage[key] = new_node
84+
85+
# updating position to most recently used
86+
def get(self,key):
87+
if key not in self.storage:
7588
return None
76-
77-
node = self.data[key]
78-
79-
# moving node to front because was used
80-
if node != self.first:
81-
82-
if node.prev:
83-
node.prev.next = node.next
84-
if node.next:
85-
node.next.prev = node.prev
86-
87-
if node == self.last:
88-
self.last = node.prev
89-
90-
node.prev = None
91-
node.next = self.first
92-
self.first.prev = node
93-
self.first = node
94-
89+
node = self.storage[key]
90+
self.touch(node)
9591
return node.value

0 commit comments

Comments
 (0)