python基於雙向鏈表實現LFU算法

本文實例為大傢分享瞭python實現LFU算法的具體代碼,供大傢參考,具體內容如下

在第一節中實現瞭雙向鏈表DoubleLinkedList類,上一節中基於雙向鏈表實現瞭LRU算法,本節課我們繼續基於雙向鏈表實現LFU(Least frequently used 最不經常使用)算法。

一、重寫Node節點類

構建LFUNode類 繼承自第一節中的Node類,添加freq屬性用來表示節點使用頻率

class LFUNode(Node):

    def __init__(self, key, value):
        """
        LFU節點 增加頻率屬性
        :param key:
        :param value:
        """
        self.freq = 0
        super(LFUNode, self).__init__(key, value)

二、LFU實現

LFU的實現除瞭get和put之外還有一個私有的__update_freq更新節點頻率方法,讀寫某節點時都需要對該節點的頻率屬性進行更新。除瞭map之外新增加一個freq_map來存儲每個頻率下的雙向鏈表,當達到最大容量時移除最小頻率下的頭部的節點。

class LFUCache(object):

    def __init__(self, capacity=0xffffffff):
        """
        LFU緩存置換算法 最不經常使用
        :param capacity:
        """
        self.capacity = capacity
        self.size = 0
        self.map = {}
        self.freq_map = {}

    def __update_freq(self, node):
        """
        更新節點頻率
        :param node:
        :return:
        """
        freq = node.freq

        # 當前節點所在頻率存在 在當前頻率鏈表中移除當前節點
        if freq in self.freq_map:
            node = self.freq_map[freq].remove(node)
            # 當前頻率鏈表為空時刪除該頻率鏈表
            if self.freq_map[freq].size == 0:
                del self.freq_map[freq]

        # 將節點按照新頻率寫入頻率鏈表
        freq += 1
        node.freq = freq
        if freq not in self.freq_map:
            self.freq_map[freq] = DoubleLinkedList()
        self.freq_map[freq].append(node)

        return node

    def get(self, key):
        """
        獲取元素
        :return:
        """
        # 節點不存在
        if key not in self.map:
            return None

        # 節點存在 更新使用頻率
        old_node = self.map.get(key)
        new_node = self.__update_freq(old_node)
        self.map[key] = new_node

        return new_node.value

    def put(self, key, value):
        """
        設置元素
        :param key:
        :param value:
        :return:
        """
        # 節點已存在 更新頻率
        if key in self.map:
            old_node = self.map.get(key)
            old_node.value = value
            new_node = self.__update_freq(old_node)
            self.map[key] = new_node
        else:
            # 節點容量達到上限 移除最小頻率鏈表頭部的節點
            if self.size >= self.capacity:
                min_freq = min(self.freq_map)
                node = self.freq_map[min_freq].pop()
                del self.map[node.key]
                self.size -= 1

            # 構建新的節點 更新頻率
            new_node = LFUNode(key, value)
            new_node = self.__update_freq(new_node)
            self.map[key] = new_node
            self.size += 1

        return new_node

    def print(self):
        """
        打印當前鏈表
        :return:
        """
        for freq, link in self.freq_map.items():
            print("frequencies: %d" % freq)
            link.print()

三、測試邏輯

if __name__ == '__main__':
    lfu_cache = LFUCache(4)
    lfu_cache.put(1, 1)
    lfu_cache.print()
    lfu_cache.put(2, 2)
    lfu_cache.print()
    print(lfu_cache.get(1))
    lfu_cache.print()
    lfu_cache.put(3, 3)
    lfu_cache.print()
    lfu_cache.put(4, 4)
    lfu_cache.print()
    lfu_cache.put(5, 5)
    lfu_cache.print()
    print(lfu_cache.get(2))
    lfu_cache.put(4, 400)
    lfu_cache.print()

測試結果:

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: