同步操作将从 编程语言算法集/Python 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
from __future__ import annotationsfrom collections.abc import Callablefrom typing import Generic, TypeVarT = TypeVar("T")U = TypeVar("U")class DoubleLinkedListNode(Generic[T, U]):"""Double Linked List Node built specifically for LFU Cache>>> node = DoubleLinkedListNode(1,1)>>> nodeNode: key: 1, val: 1, freq: 0, has next: False, has prev: False"""def __init__(self, key: T | None, val: U | None):self.key = keyself.val = valself.freq: int = 0self.next: DoubleLinkedListNode[T, U] | None = Noneself.prev: DoubleLinkedListNode[T, U] | None = Nonedef __repr__(self) -> str:return (f"Node: key: {self.key}, val: {self.val}, freq: {self.freq}, "f"has next: {self.next is not None}, has prev: {self.prev is not None}")class DoubleLinkedList(Generic[T, U]):"""Double Linked List built specifically for LFU Cache>>> dll: DoubleLinkedList = DoubleLinkedList()>>> dllDoubleLinkedList,Node: key: None, val: None, freq: 0, has next: True, has prev: False,Node: key: None, val: None, freq: 0, has next: False, has prev: True>>> first_node = DoubleLinkedListNode(1,10)>>> first_nodeNode: key: 1, val: 10, freq: 0, has next: False, has prev: False>>> dll.add(first_node)>>> dllDoubleLinkedList,Node: key: None, val: None, freq: 0, has next: True, has prev: False,Node: key: 1, val: 10, freq: 1, has next: True, has prev: True,Node: key: None, val: None, freq: 0, has next: False, has prev: True>>> # node is mutated>>> first_nodeNode: key: 1, val: 10, freq: 1, has next: True, has prev: True>>> second_node = DoubleLinkedListNode(2,20)>>> second_nodeNode: key: 2, val: 20, freq: 0, has next: False, has prev: False>>> dll.add(second_node)>>> dllDoubleLinkedList,Node: key: None, val: None, freq: 0, has next: True, has prev: False,Node: key: 1, val: 10, freq: 1, has next: True, has prev: True,Node: key: 2, val: 20, freq: 1, has next: True, has prev: True,Node: key: None, val: None, freq: 0, has next: False, has prev: True>>> removed_node = dll.remove(first_node)>>> assert removed_node == first_node>>> dllDoubleLinkedList,Node: key: None, val: None, freq: 0, has next: True, has prev: False,Node: key: 2, val: 20, freq: 1, has next: True, has prev: True,Node: key: None, val: None, freq: 0, has next: False, has prev: True>>> # Attempt to remove node not on list>>> removed_node = dll.remove(first_node)>>> removed_node is NoneTrue>>> # Attempt to remove head or rear>>> dll.headNode: key: None, val: None, freq: 0, has next: True, has prev: False>>> dll.remove(dll.head) is NoneTrue>>> # Attempt to remove head or rear>>> dll.rearNode: key: None, val: None, freq: 0, has next: False, has prev: True>>> dll.remove(dll.rear) is NoneTrue"""def __init__(self) -> None:self.head: DoubleLinkedListNode[T, U] = DoubleLinkedListNode(None, None)self.rear: DoubleLinkedListNode[T, U] = DoubleLinkedListNode(None, None)self.head.next, self.rear.prev = self.rear, self.headdef __repr__(self) -> str:rep = ["DoubleLinkedList"]node = self.headwhile node.next is not None:rep.append(str(node))node = node.nextrep.append(str(self.rear))return ",\n ".join(rep)def add(self, node: DoubleLinkedListNode[T, U]) -> None:"""Adds the given node at the tail of the list and shifting it to proper position"""previous = self.rear.prev# All nodes other than self.head are guaranteed to have non-None previousassert previous is not Noneprevious.next = nodenode.prev = previousself.rear.prev = nodenode.next = self.rearnode.freq += 1self._position_node(node)def _position_node(self, node: DoubleLinkedListNode[T, U]) -> None:"""Moves node forward to maintain invariant of sort by freq value"""while node.prev is not None and node.prev.freq > node.freq:# swap node with previous nodeprevious_node = node.prevnode.prev = previous_node.prevprevious_node.next = node.prevnode.next = previous_nodeprevious_node.prev = nodedef remove(self, node: DoubleLinkedListNode[T, U]) -> DoubleLinkedListNode[T, U] | None:"""Removes and returns the given node from the listReturns None if node.prev or node.next is None"""if node.prev is None or node.next is None:return Nonenode.prev.next = node.nextnode.next.prev = node.prevnode.prev = Nonenode.next = Nonereturn nodeclass LFUCache(Generic[T, U]):"""LFU Cache to store a given capacity of data. Can be used as a stand-alone objector as a function decorator.>>> cache = LFUCache(2)>>> cache.put(1, 1)>>> cache.put(2, 2)>>> cache.get(1)1>>> cache.put(3, 3)>>> cache.get(2) is NoneTrue>>> cache.put(4, 4)>>> cache.get(1) is NoneTrue>>> cache.get(3)3>>> cache.get(4)4>>> cacheCacheInfo(hits=3, misses=2, capacity=2, current_size=2)>>> @LFUCache.decorator(100)... def fib(num):... if num in (1, 2):... return 1... return fib(num - 1) + fib(num - 2)>>> for i in range(1, 101):... res = fib(i)>>> fib.cache_info()CacheInfo(hits=196, misses=100, capacity=100, current_size=100)"""# class variable to map the decorator functions to their respective instancedecorator_function_to_instance_map: dict[Callable[[T], U], LFUCache[T, U]] = {}def __init__(self, capacity: int):self.list: DoubleLinkedList[T, U] = DoubleLinkedList()self.capacity = capacityself.num_keys = 0self.hits = 0self.miss = 0self.cache: dict[T, DoubleLinkedListNode[T, U]] = {}def __repr__(self) -> str:"""Return the details for the cache instance[hits, misses, capacity, current_size]"""return (f"CacheInfo(hits={self.hits}, misses={self.miss}, "f"capacity={self.capacity}, current_size={self.num_keys})")def __contains__(self, key: T) -> bool:""">>> cache = LFUCache(1)>>> 1 in cacheFalse>>> cache.put(1, 1)>>> 1 in cacheTrue"""return key in self.cachedef get(self, key: T) -> U | None:"""Returns the value for the input key and updates the Double Linked List. ReturnsReturns None if key is not present in cache"""if key in self.cache:self.hits += 1value_node: DoubleLinkedListNode[T, U] = self.cache[key]node = self.list.remove(self.cache[key])assert node == value_node# node is guaranteed not None because it is in self.cacheassert node is not Noneself.list.add(node)return node.valself.miss += 1return Nonedef put(self, key: T, value: U) -> None:"""Sets the value for the input key and updates the Double Linked List"""if key not in self.cache:if self.num_keys >= self.capacity:# delete first node when over capacityfirst_node = self.list.head.next# guaranteed to have a non-None first node when num_keys > 0# explain to type checker via assertionsassert first_node is not Noneassert first_node.key is not Noneassert self.list.remove(first_node) is not None# first_node guaranteed to be in listdel self.cache[first_node.key]self.num_keys -= 1self.cache[key] = DoubleLinkedListNode(key, value)self.list.add(self.cache[key])self.num_keys += 1else:node = self.list.remove(self.cache[key])assert node is not None # node guaranteed to be in listnode.val = valueself.list.add(node)@classmethoddef decorator(cls: type[LFUCache[T, U]], size: int = 128) -> Callable[[Callable[[T], U]], Callable[..., U]]:"""Decorator version of LFU CacheDecorated function must be function of T -> U"""def cache_decorator_inner(func: Callable[[T], U]) -> Callable[..., U]:def cache_decorator_wrapper(*args: T) -> U:if func not in cls.decorator_function_to_instance_map:cls.decorator_function_to_instance_map[func] = LFUCache(size)result = cls.decorator_function_to_instance_map[func].get(args[0])if result is None:result = func(*args)cls.decorator_function_to_instance_map[func].put(args[0], result)return resultdef cache_info() -> LFUCache[T, U]:return cls.decorator_function_to_instance_map[func]setattr(cache_decorator_wrapper, "cache_info", cache_info) # noqa: B010return cache_decorator_wrapperreturn cache_decorator_innerif __name__ == "__main__":import doctestdoctest.testmod()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。