![]()
1 #! -*- encoding=utf-8 -*-
2
3 from DoubleLinkedList import DoubleLinkedList, Node
4
5
6 class LFUNode(Node): # 继承Node
7 def __init__(self, key, value):
8 self.freq = 0 # 用于记录节点的使用频率
9 super(LFUNode, self).__init__(key, value)
10
11
12 class LFUCache(object):
13
14 def __init__(self, capacity):
15 self.capacity = capacity
16 self.map = {}
17 # key用来存储频率:value用来存储有相同Node,使用DoubleLinkedList来存储
18 self.freq_map = {}
19 self.size = 0 # 这里定义size是因为没有一个装有所有node的List,需要size来判断容量是否已满 , 需要在每一次put是做处理
20 # self.list = DoubleLinkedList(self.capacity) # 如果定义出来唯一的作用就是 list.size 判断缓存是否已满 ,这里选择删去
21
22 # 更新节点频率的操作 , 此为本算法的核心
23 def __update_freq(self, node):
24 freq = node.freq
25
26 # 删除
27 node = self.freq_map[freq].remove(node)
28 if self.freq_map[freq].size == 0:
29 del self.freq_map[freq]
30
31 # 更新
32 freq += 1
33 node.freq = freq
34 if freq not in self.freq_map: # 如果还没有这个频率的双向链表就创建一个
35 self.freq_map[freq] = DoubleLinkedList()
36 self.freq_map[freq].append(node)
37
38 # 每次使用了某个节点后,节点的使用频率都需要+1,并且需要更换到所更新频率对应的频率链表中
39 def get(self, key):
40 if key not in self.map:
41 return -1
42 node = self.map[key]
43 self.__update_freq(node)
44 return node.value
45
46 def put(self, key, value):
47 if self.capacity == 0:
48 return
49 # 缓存命中
50 if key in self.map: # key已经在缓存中时
51 node = self.map.get(key)
52 node.value = value
53 self.__update_freq(node) # 修改了值,cpu需要使用缓存时会对此缓存的时效性进行判断,则修改值也算作为一次使用
54
55 # 缓存未命中
56 else: # key未在缓存中
57 if self.size >= self.capacity: # 缓存容量已满,则需要弹出一个最近最少使用的节点
58 min_freq = min(self.freq_map) # 找出最小的key
59 node = self.freq_map[min_freq].pop() # 删除key=min_freq:value=DoubleLinkedList中value里的第一个节点(最先被加入的在头,后加入的在尾部)
60 del self.map[node.key] # 在本地中删除这个node
61 self.size -= 1
62 node = LFUNode(key, value) # 缓存容量未满
63 node.freq = 1 # 把频率改为1,因为如果被加入缓存中则至少被使用过一次
64 self.map[key] = node # 在确定了freq后就可以被加入map
65 # 新的节点需要被加入到freq_map中,频率key=1,value=DoubleLinkedList,若元祖中没有关于key=1,则创建
66 if node.freq not in self.freq_map: # 如果频率中没有关于1的链表
67 self.freq_map[node.freq] = DoubleLinkedList()
68 self.freq_map[node.freq].append(node) # 如果已经存在则直接把node加入到此DoubleLinkedList的末尾
69 self.size += 1 # 缓存容量+1
70
71 def print(self):
72 print("****************************")
73 for k, v in self.freq_map.items(): # 遍历freq_map
74 print('Freq = %d' % k) # K既是频率,打印
75 # print(self.freq_map[k]) # 这样print只能打印出地址
76 self.freq_map[k].print()
77 print("*****************************")
78 print()
79
80
81 if __name__ == '__main__':
82 cache = LFUCache(2)
83 cache.put(1, 1)
84 cache.print()
85 cache.put(2, 2)
86 cache.print()
87 print(cache.get(1))
88 cache.print()
89
90 cache.put(3, 3)
91 cache.print()
92 print(cache.get(2))
93 cache.print()
94 print(cache.get(3))
95 cache.print()
96 cache.put(4, 4)
97 cache.print()
98 print(cache.get(1))
99 cache.print()
100 print(cache.get(3))
101 cache.print()
102 print(cache.get(4))
103 cache.print()