Skip to content

Commit 936d05b

Browse files
committed
Add LRU
1 parent b3a7aa9 commit 936d05b

File tree

9 files changed

+454
-621
lines changed

9 files changed

+454
-621
lines changed

dataStructure/LRU/allOne.py

+187
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
''' mbinary
2+
#########################################################################
3+
# File : allOne.py
4+
# Author: mbinary
5+
6+
# Blog: https://mbinary.xyz
7+
# Github: https://github.com/mbinary
8+
# Created Time: 2018-05-19 23:07
9+
# Description:
10+
#########################################################################
11+
'''
12+
13+
14+
class node:
15+
def __init__(self, val=None, keys=None, pre=None, next=None):
16+
self.val = val
17+
self.keys = set() if keys is None else keys
18+
self.pre = pre
19+
self.next = next
20+
21+
def __lt__(self, nd):
22+
return self.val < nd.val
23+
24+
25+
def __contains__(self, k):
26+
return k in self.keys
27+
28+
def __bool__(self):
29+
return len(self.keys) != 0
30+
31+
def __repr__(self):
32+
return 'node({},{})'.format(self.val, self.keys)
33+
def addKey(self, key):
34+
self.keys.add(key)
35+
36+
37+
def remove(self, key):
38+
self.keys.remove(key)
39+
40+
def getOneKey(self):
41+
if self:
42+
key = self.keys.pop()
43+
self.keys.add(key)
44+
return key
45+
return None
46+
47+
48+
class allOne:
49+
def __init__(self):
50+
self.head = self.tail = node(0)
51+
self.head.next = self.head
52+
self.head.pre = self.head
53+
self.val_node = {0: self.head}
54+
self.key_value = {}
55+
56+
def __str__(self):
57+
li = list(self.val_node.values())
58+
li = [str(i) for i in li]
59+
return 'min:{}, max:{}\n'.format(self.head.val,self.tail.val) \
60+
+ '\n'.join(li)
61+
def __contains__(self,k):
62+
return k in self.key_value
63+
64+
def getMaxKey(self):
65+
return self.tail.getOneKey()
66+
67+
def getMinKey(self):
68+
return self.head.getOneKey()
69+
70+
def getMaxVal(self):
71+
k = self.getMaxKey()
72+
if k is not None:
73+
return self.key_value[k]
74+
75+
def getMinVal(self):
76+
k = self.getMinKey()
77+
if k is not None:
78+
return self.key_value[k]
79+
80+
def addIncNode(self, val):
81+
# when adding a node,inc 1, so it's guranted that node(val-1) exists
82+
self.val_node[val] = node(val)
83+
self.val_node[val].pre = self.val_node[val - 1]
84+
self.val_node[val].next = self.val_node[val - 1].next
85+
self.val_node[val - 1].next.pre = self.val_node[
86+
val - 1].next = self.val_node[val]
87+
if self.tail.val < val:
88+
self.tail = self.val_node[val]
89+
if self.head.val > val or self.head.val == 0:
90+
self.head = self.val_node[val]
91+
92+
def addDecNode(self, val):
93+
# when adding a node,dec 1, so it's guranted that node(val+1) exists
94+
self.val_node[val] = node(val)
95+
self.val_node[val].next = self.val_node[val + 1]
96+
self.val_node[val].pre = self.val_node[val + 1].pre
97+
self.val_node[val + 1].pre.next = self.val_node[
98+
val + 1].pre = self.val_node[val]
99+
if self.head.val > val:
100+
self.head = self.val_node[val]
101+
102+
def delNode(self, val):
103+
self.val_node[val].next.pre = self.val_node[val].pre
104+
self.val_node[val].pre.next = self.val_node[val].next
105+
if self.tail.val == val: self.tail = self.val_node[val].pre
106+
if self.head.val == val: self.head = self.val_node[val].next
107+
del self.val_node[val]
108+
109+
def inc(self, key):
110+
''' inc key to value val'''
111+
val = 1
112+
if key in self.key_value:
113+
val += self.key_value[key]
114+
self.key_value[key] = val
115+
if val not in self.val_node:
116+
self.addIncNode(val)
117+
self.val_node[val].addKey(key)
118+
if val != 1: # key in the pre node
119+
preVal = val - 1
120+
nd = self.val_node[preVal]
121+
if key in nd:
122+
nd.remove(key)
123+
if not nd:
124+
self.delNode(preVal)
125+
126+
def dec(self, key):
127+
if key in self.key_value:
128+
self.key_value[key] -= 1
129+
val = self.key_value[key]
130+
if val == 0:
131+
del self.key_value[key]
132+
elif val>0:
133+
if val not in self.val_node:
134+
self.addDecNode(val)
135+
# notice that the headnode(0) shouldn't add key
136+
self.val_node[val].addKey(key)
137+
nextVal = val + 1
138+
nd = self.val_node[nextVal]
139+
if key in nd:
140+
nd.remove(key)
141+
if not nd:
142+
self.delNode(nextVal)
143+
144+
def delMinKey(self):
145+
key = self.getMinKey()
146+
if key is not None:
147+
val = self.key_value.pop(key)
148+
nd = self.val_node[val]
149+
nd.remove(key)
150+
if not nd:
151+
self.delNode(val)
152+
return key
153+
def append(self,key):
154+
if key in self.key_value:
155+
raise Exception(f'[Error]: key "{key}" exists')
156+
if self.key_value:
157+
val = self.key_value[self.getMaxKey()]
158+
self.key_value[key] = val
159+
self.val_node[val].addKey(key)
160+
self.inc(key)
161+
def move_to_end(self,key):
162+
val = self.key_value.pop(key)
163+
nd = self.val_node[val]
164+
nd.remove(key)
165+
if not nd:
166+
self.delNode(val)
167+
self.append(key)
168+
169+
170+
171+
if __name__ == '__main__':
172+
ops = [
173+
"inc", "inc", "inc", "inc", "inc", "dec", "dec", "getMaxKey",
174+
"getMinKey",'dec'
175+
]
176+
obj = allOne()
177+
data = [["a"], ["b"], ["b"], ["b"], ["b"], ["b"], ["b"], [], [],['a']]
178+
operate = {
179+
"inc": obj.inc,
180+
"dec": obj.dec,
181+
"getMaxKey": obj.getMaxKey,
182+
"getMinKey": obj.getMinKey
183+
}
184+
for op, datum in zip(ops, data):
185+
print(f'{op}({datum}): {operate[op](*datum)}')
186+
print(obj)
187+
print()

dataStructure/LRU/lru_allone.py

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from allOne import allOne
2+
3+
'''In this implementation, the lru doesn't use some funcs of allOne,
4+
such as dec,addDecNode
5+
'''
6+
class lru:
7+
def __init__(self, capacity):
8+
self.capacity = capacity
9+
self.allOne = allOne()
10+
self.data = {}
11+
def get(self,key):
12+
if key in self.data:
13+
self.allOne.move_to_end(key)
14+
return self.data[key]
15+
return -1
16+
def put(self,key,value):
17+
if key not in self.data:
18+
if len(self.data)==self.capacity:
19+
k = self.allOne.delMinKey()
20+
if k in self.data:
21+
del self.data[k]
22+
self.data[key]=value
23+
self.allOne.append(key)
24+
else:
25+
self.data[key]=value
26+
self.allOne.move_to_end(key)
27+
28+
29+
if __name__ == '__main__':
30+
ops = ["put","put","get","put","get","put","get","get","get"]
31+
data = [[1,1],[2,2],[1],[3,3],[2],[4,4],[1],[3],[4]]
32+
obj = lru(2)
33+
operate = {'get':obj.get,'put':obj.put}
34+
for op, args in zip(ops,data):
35+
print(f'{op}({args}): {operate[op](*args)}\n{obj.data}\n')
36+

dataStructure/LRU/lru_orderedDict.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class LRUCache(object):
2+
3+
def __init__(self, capacity):
4+
self.od, self.cap = collections.OrderedDict(), capacity
5+
6+
def get(self, key):
7+
if key not in self.od: return -1
8+
self.od.move_to_end(key)
9+
return self.od[key]
10+
11+
def put(self, key, value):
12+
if key in self.od: del self.od[key]
13+
elif len(self.od) == self.cap: self.od.popitem(False)
14+
self.od[key] = value

dataStructure/allOone/test.py renamed to dataStructure/LRU/test_allone.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#########################################################################
1111
'''
1212

13-
from allOone import AllOne
13+
from allOne import allOne
1414
from time import time
1515
from random import choice,sample,randint
1616

@@ -49,12 +49,18 @@ def testCase(n=1000):
4949
def test(repeat=100):
5050
t1,t2=0,0
5151
for i in range(repeat):
52-
allOne = AllOne()
52+
obj = allOne()
53+
operate = {
54+
"inc": obj.inc,
55+
"dec": obj.dec,
56+
"getMaxKey": obj.getMaxKey,
57+
"getMinKey": obj.getMinKey
58+
}
5359
hsmp = hashMap()
5460
ops,data = testCase()
5561
t1-=time()
5662
for op,datum in zip(ops,data):
57-
allOne.op[op](*datum)
63+
operate[op](*datum)
5864
t1+=time()
5965

6066
t2-=time()
@@ -66,5 +72,5 @@ def test(repeat=100):
6672

6773
if __name__=='__main__':
6874
t1,t2= test()
69-
print(f'allOone: {t1}')
75+
print(f'allOne: {t1}')
7076
print(f'hashmap: {t2}')

0 commit comments

Comments
 (0)