zoukankan      html  css  js  c++  java
  • python实现LRU置换算法、LFU置换算法(补充self.map的使用和字典的方法)

    关于本地存放的映射关系map:

    本质上是一个空字典:self.map={}

    每次新增一个节点node,都会把node的key, value放入map中: self.map[key] = node ==> self.map的样子应该是{key1:node1, key2:node2}  (注意:node是一个自定义的新的类,详见:https://www.cnblogs.com/marvintang1001/p/11125619.html )

    取出字典一个键值对(返回的是值): node = self.map[key]  这是非安全方法,如果没有这个key会报错。安全方法:value = my_dict.get("key")  如果没有这个键就返回None。) 

    删除字典一对键值的方法: self.map.pop(key)  或者是  del self.map[key]

    for k, v in self.freq_map.items():  字典的items方法:返回可遍历的(键, 值) 元组数组

    *关于字典的应用:https://www.cnblogs.com/lowmanisbusy/p/9142199.html


    LRU(最近最少使用)算法:

    每次使用,把使用的节点放到链表最前面

    淘汰缓存时,把链表尾部的节点淘汰

    #! -*- encoding=utf-8 -*-
    
    from computer_principle.doublelinkedlist import DoubleLinkedList, Node
    
    
    class LRUCache(object):
    
        def __init__(self, capacity):
            self.capacity = capacity
            self.map = {}  # 保存key和value的映射关系
            self.list = DoubleLinkedList(self.capacity)
    
        # 每次使用,把使用的节点放到链表最前面,返回值
        def get(self, key):
            if key in self.map:
                node = self.map[key]      # 取出这个key和它的值
                self.list.remove(node)
                self.list.append_front(node)    #把这个缓存放到最前面
                return node.value
            else:
                return -1
    
        #添加一个缓存
        def put(self, key, value):
            # 先判断key是否已经在缓存里:
            if key in self.map:     #是在缓存里:更新value,放入最前面
                node = self.map.get(key)
                self.list.remove(node)
                node.value = value
                self.list.append_front(node)
            else:
                node = Node(key, value)
                #缓存已经满了的话需要先删掉最后一个再往head增加新的:
                if self.list.size >= self.list.capacity-1:
                    old_node = self.list.remove()
                    self.map.pop(old_node.key)  #删除节点同时要删除本地映射
    
                self.list.append_front(node)
                self.map[key] = node
    
        def print(self):
            self.list.print()
    
    # test:
    if __name__ == '__main__':
        cache = LRUCache(2)
        cache.put(2, 2)
        cache.print()
        cache.put(1, 1)
        cache.print()
        cache.put(3, 3)  # 淘汰了(1,1)
        cache.print()
        print(cache.get(1))
        cache.print()
        print(cache.get(2))
        cache.print()
        print(cache.get(3))
        cache.print()

    结果:

    {2: 2}
    {1: 1}=>{2: 2}
    {3: 3}=>{1: 1}
    1
    {1: 1}=>{3: 3}
    -1
    {1: 1}=>{3: 3}
    3
    {3: 3}=>{1: 1}


    LFU(最不经常使用)算法:

    淘汰缓存时,把使用频率最小的淘汰

    存在相同频率的情况:每个频率单独做一个双向链表,淘汰时把最低频率的head节点淘汰掉(FIFO)

    #! -*- encoding=utf-8 -*-
    
    from computer_principle.doublelinkedlist import DoubleLinkedList, Node
    
    class LFUNode(Node):
        def __init__(self, key, value):
            self.freq = 0   # 新增一个freq属性
            super(LFUNode, self).__init__(key, value)   # 这是python2的写法。python3:super().__init__(key, value)
    
    
    class LFUCache():
        def __init__(self, capacity):
            self.capacity = capacity
            self.map = {}  # 保存key和value的映射关系
            # key: 频率, value:频率对应的双向链表
            self.freq_map = {}
            self.list = DoubleLinkedList(self.capacity)
            self.size = 0
    
        # 更新节点频率的操作
        def __update_freq(self, node):
            freq = node.freq    # 这个节点之前所在的频率的双向链表
    
            # 删除:
            node = self.freq_map[freq].remove(node)
            if self.freq_map[freq].size == 0:
                del self.freq_map[freq]
    
            # 更新:
            freq = freq+1
            node.freq = freq
            if freq not in self.freq_map:
                self.freq_map[freq] = DoubleLinkedList()
            self.freq_map[freq].append(node)
    
    
        def get(self, key):
            if key not in self.map:
                return -1
            node = self.map.get(key)
            self.__update_freq(node)
            return node.value
    
    
        def put(self, key, value):
            if self.capacity == 0:
                return
    
            # 缓存命中:
            if key in self.map:
                node = self.map.get(key)
                node.value = value
                self.__update_freq(node)
    
            # 缓存没有命中:
            else:
                # 判读缓存是否满了:
                if self.capacity == self.size:
                    # 满了就淘汰频率最低,最早进去的那个缓存:
                    min_freq = min(self.freq_map)       #freq_map里的key都是数字
                    node = self.freq_map[min_freq].pop()    #默认pop是head
                    del self.map[node.key]
                    self.size -= 1
                # 下面是不管是否命中都会执行的步骤:
                node = LFUNode(key, value)
                node.freq = 1
                self.map[key] = node
                if node.freq not in self.freq_map:
                    self.freq_map[node.freq] = DoubleLinkedList()
                node = self.freq_map[node.freq].append(node)
                self.size += 1
    
        def print(self):
            print('****************************')
            for k, v in self.freq_map.items():      # 字典的items方法:返回可遍历的(键, 值) 元组数组
                print('Freq = {}'.format(k))
                self.freq_map[k].print()
            print('****************************')
            print()
    
    # test:
    if __name__ == '__main__':
        cache = LFUCache(2)
        cache.put(1, 1)
        cache.print()
        cache.put(2, 2)
        cache.print()
        print(cache.get(1))
        cache.print()
        cache.put(3, 3)
        cache.print()
        print(cache.get(2))
        cache.print()
        print(cache.get(3))
        cache.print()
        cache.put(4, 4)
        cache.print()
        print(cache.get(1))
        cache.print()
        # print(cache.get(2))
        print(cache.get(3))
        cache.print()
        print(cache.get(4))
        cache.print()

    结果:

    ****************************
    Freq = 1
    {1: 1}
    ****************************

    ****************************
    Freq = 1
    {1: 1}=>{2: 2}
    ****************************

    1
    ****************************
    Freq = 1
    {2: 2}
    Freq = 2
    {1: 1}
    ****************************

    ****************************
    Freq = 1
    {3: 3}
    Freq = 2
    {1: 1}
    ****************************

    -1
    ****************************
    Freq = 1
    {3: 3}
    Freq = 2
    {1: 1}
    ****************************

    3
    ****************************
    Freq = 2
    {1: 1}=>{3: 3}
    ****************************

    ****************************
    Freq = 2
    {3: 3}
    Freq = 1
    {4: 4}
    ****************************

    -1
    ****************************
    Freq = 2
    {3: 3}
    Freq = 1
    {4: 4}
    ****************************

    3
    ****************************
    Freq = 1
    {4: 4}
    Freq = 3
    {3: 3}
    ****************************

    4
    ****************************
    Freq = 3
    {3: 3}
    Freq = 2
    {4: 4}
    ****************************

  • 相关阅读:
    第二阶段冲刺总结01
    第十四周学习进度
    第十三周进度
    意见改进
    BZOJ 2109 航空管制(拓扑排序+贪心)
    BZOJ 2131 圈地计划(最小割+黑白染色)
    BZOJ 2118 墨墨的等式(最短路)
    BZOJ 2157 旅行(树链剖分码农题)
    BZOJ 2141 排队(树状数组套主席树)
    BZOJ 2186 沙拉公主的困惑(预处理逆元+欧拉函数)
  • 原文地址:https://www.cnblogs.com/marvintang1001/p/11127315.html
Copyright © 2011-2022 走看看