|
4 | 4 |
|
5 | 5 | 这里学习下 LRU(least frequently used),就是当缓存满了之后剔除一个最少使用的 key。
|
6 | 6 | """
|
| 7 | +from collections import defaultdict, OrderedDict |
| 8 | + |
| 9 | + |
| 10 | +class Node: |
| 11 | + __slots__ = 'key', 'val', 'cnt' |
| 12 | + |
| 13 | + def __init__(self, key, val, cnt=0): |
| 14 | + self.key, self.val, self.cnt = key, val, cnt |
| 15 | + |
| 16 | + |
| 17 | +class LFUCache: |
| 18 | + def __init__(self, capacity): |
| 19 | + self.capacity = capacity |
| 20 | + self.cache = {} # type {key: node} |
| 21 | + self.cnt2node = defaultdict(OrderedDict) |
| 22 | + self.mincnt = 0 |
| 23 | + |
| 24 | + def get(self, key, default=-1): |
| 25 | + if key not in self.cache: |
| 26 | + return default |
| 27 | + |
| 28 | + node = self.cache[key] |
| 29 | + del self.cnt2node[node.cnt][key] |
| 30 | + |
| 31 | + if not self.cnt2node[node.cnt]: |
| 32 | + del self.cnt2node[node.cnt] |
| 33 | + |
| 34 | + node.cnt += 1 |
| 35 | + self.cnt2node[node.cnt][key] = node |
| 36 | + |
| 37 | + if not self.cnt2node[self.mincnt]: |
| 38 | + self.mincnt += 1 |
| 39 | + return node.val |
| 40 | + |
| 41 | + def put(self, key, value): |
| 42 | + if key in self.cache: |
| 43 | + self.cache[key].val = value |
| 44 | + self.get(key) |
| 45 | + return |
| 46 | + if len(self.cache) >= self.capacity: |
| 47 | + pop_key, _pop_node = self.cnt2node[self.mincnt].popitem(last=False) |
| 48 | + del self.cache[pop_key] |
| 49 | + |
| 50 | + self.cache[key] = self.cnt2node[1][key] = Node(key, value, 1) |
| 51 | + self.mincnt = 1 |
| 52 | + |
| 53 | + |
| 54 | +def test(): |
| 55 | + c = LFUCache(2) |
| 56 | + c.put(1, 1) |
| 57 | + c.put(2, 2) |
| 58 | + assert c.get(1) == 1 |
| 59 | + c.put(3, 3) |
| 60 | + assert c.get(2) == -1 |
| 61 | + assert c.get(3) == 3 |
| 62 | + c.put(4, 4) |
| 63 | + assert c.get(1) == -1 |
| 64 | + assert c.get(3) == 3 |
| 65 | + assert c.get(4) == 4 |
| 66 | + |
| 67 | + |
| 68 | +if __name__ == '__main__': |
| 69 | + test() |
0 commit comments