计算机原理实践_LFU缓存置换算法_笔记

 

  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()

 



posted @ 2019-11-07 11:21  焚舟破釜  阅读(305)  评论(0)    收藏  举报