Claude Haiku 5 5 在「实现缓存淘汰算法」的评测结果
这是该 AI 模型在此测试用例上的详细评测结果。
基本信息
- 模型名称:Claude Haiku 5 5
- 用例名称:实现缓存淘汰算法
- 测试类型:文本生成
- 评测维度:代码生成
系统提示词(System Prompt)
这是给 AI 模型的背景设定和角色指令:
你是一名资深软件工程师,擅长数据结构与算法设计,尤其熟悉各类缓存机制的原理与实现。 回答要求: 1. 使用 Python 语言实现,代码需包含必要的注释,解释关键逻辑。 2. 实现完成后,简要说明你选择该数据结构的原因(1-3 句话即可)。 3. 提供至少 3 个测试用例(包含正常流程、缓存满时的淘汰行为、以及边界情况),并展示预期输出。 4. 代码需具备良好的可读性:变量命名清晰,逻辑层次分明。
用户提示词(User Prompt)
这是用户给 AI 模型的具体任务要求:
请使用 Python 实现一个 FIFO(先进先出)缓存类 `FIFOCache`,要求如下: **功能要求:** - `__init__(self, capacity: int)`:初始化缓存,`capacity` 为缓存的最大容量(正整数)。 - `get(self, key: int) -> int`:若 `key` 存在于缓存中,返回对应的值;否则返回 `-1`。 - `put(self, key: int, value: int) -> None`:将键值对写入缓存。 - 若 `key` 已存在,则**更新**其对应的值(不改变该 key 在队列中的位置,即不影响淘汰顺序)。 - 若 `key` 不存在且缓存已满,则**先淘汰最早加入**的那个 key,再插入新键值对。 - 若缓存未满,直接插入。 **边界情况说明:** - `capacity` 保证为正整数(≥ 1),无需处理容量为 0 的情况。 - `key` 和 `value` 均为非负整数。 **示例:**
任务要求
AI 模型需要满足以下要求:
- 必须手动实现双向链表节点类(含 prev/next 指针),不得借助 OrderedDict 等内置有序容器,否则核心算法得分为 0。
- get 和 put 操作均需达到严格的 O(1) 时间复杂度,需在代码注释或说明中给出分析依据。
- 缓存满时的淘汰逻辑必须正确:淘汰链表尾部(最久未使用)节点,同时同步删除哈希表中对应的 key。
- 对已存在 key 执行 put 时,必须正确更新值并将节点移动到链表头部(标记为最近使用),而非插入新节点。
- 测试用例需覆盖至少 4 种场景:正常读写命中、缓存未满时的插入、缓存满时的淘汰、对已有 key 的更新后顺序验证。
- 代码结构清晰,变量命名语义明确,关键操作(如节点插入头部、从链表移除节点)应封装为独立的私有方法。
评测结果
综合得分
该模型在此用例的得分为:98.5 分(满分 100 分),已通过
基础难度评测结果
- 得分:98.5 分
- 通过状态:已通过
模型生成产物
以下是该模型针对此任务的实际生成内容:
## 实现代码 ```python from collections import deque class FIFOCache: """ 基于哈希表 + 双端队列的 FIFO 缓存。 - dict(self._store):保存 key -> value,实现 O(1) 的查找与更新。 - deque(self._order):按插入顺序记录 key,队首为最早加入的 key,实现 O(1) 的淘汰。 """ def __init__(self, capacity: int): """初始化缓存,capacity 为最大容量(正整数)。""" self._capacity = capacity self._store: dict[int, int] = {} # key -> value self._order: deque[int] = deque() # 记录 key 的插入顺序,队首最早 def get(self, key: int) -> int: """ 若 key 存在则返回对应的值,否则返回 -1。 FIFO 策略下读取操作不影响淘汰顺序,因此不调整队列。 """ return self._store.get(key, -1) def put(self, key: int, value: int) -> None: """写入键值对。""" # 情况 1:key 已存在 —— 只更新值,不改变其在队列中的位置 if key in self._store: self._store[key] = value return # 情况 2:key 不存在且缓存已满 —— 淘汰最早加入的 key if len(self._store) >= self._capacity: oldest_key = self._order.popleft() # 队首即最早插入的 key del self._store[oldest_key] # 情况 3:插入新 key(缓存未满或已完成淘汰) self._store[key] = value self._order.append(key) # 新 key 加入队尾 def __repr__(self) -> str: """便于调试:按 FIFO 顺序(最早 -> 最新)展示缓存内容。""" items = [f"{k}:{self._store[k]}" for k in self._order] return f"FIFOCache(capacity={self._capacity}, items=[{', '.join(items)}])" if __name__ == "__main__": # 示例演示 cache = FIFOCache(2) cache.put(1, 1) cache.put(2, 2) print(cache.get(1)) # 1 cache.put(3, 3) # 缓存已满,淘汰最早的 key=1 print(cache.get(2)) # 2 print(cache.get(1)) # -1 cache.put(4, 4) # 淘汰最早的 key=2 print(cache.get(2)) # -1 print(cache.get(3)) # 3 print(cache.get(4)) # 4 ``` ## 数据结构选择说明 使用“字典 + 双端队列”的组合:字典提供 O(1) 的查找与更新,双端队列按插入顺序记录 key,使队首的最早元素可以在 O(1) 时间内被淘汰。这样既满足 FIFO 的顺序要求,又避免了线性扫描。 ## 测试用例 ```python def test_normal_flow(): """测试 1:正常流程(插入、查询、未命中)""" cache = FIFOCache(3) cache.put(1, 10) cache.put(2, 20) cache.put(3, 30) assert cache.get(1) == 10 assert cache.get(2) == 20 assert cache.get(3) == 30 assert cache.get(4) == -1 # 不存在的 key print("测试 1(正常流程)通过") def test_eviction_when_full(): """测试 2:缓存满时的 FIFO 淘汰行为""" cache = FIFOCache(2) cache.put(1, 1) cache.put(2, 2) cache.put(3, 3) # 淘汰最早加入的 key=1 assert cache.get(1) == -1 assert cache.get(2)...
AI 评审点评
以下是 AI 评审对该模型输出的点评:
【CLAUDE】该回答在正确性、数据结构选型与代码质量三个维度上均表现优异。核心算法逻辑无误,数据结构选择高效且贴合 FIFO 语义,测试用例覆盖全面且超出最低要求。整体是一份接近满分的高质量实现。 【GEMINI】候选输出表现非常完美,完全满足 System Prompt 和 User Prompt 的所有功能与格式要求。算法逻辑严谨无漏洞,时间复杂度达到最优,测试用例设计兼顾典型场景与极端边界,展示了优秀的工程规范性。 【KIMI】该实现是一个完整、正确且高质量的FIFO缓存实现。算法逻辑严谨,数据结构选择合理,代码风格专业,测试覆盖全面。特别值得称赞的是对'更新已存在key不改变淘汰顺序'这一易错点的准确处理,以及容量为1和零值边界的考虑。
进阶难度评测结果
- 得分:98.4 分
- 通过状态:已通过
模型生成产物
以下是该模型针对此任务的实际生成内容:
## 设计思路 哈希表(`dict`)负责以 O(1) 定位 key 对应的节点;双向链表按访问时间维护顺序,链表头部为最近使用,尾部为最久未使用。`get` 命中时通过哈希表找到节点,再将其从链表中摘下并移到头部;`put` 插入新节点到头部,容量超出时直接淘汰尾部节点并从哈希表中删除。双向链表的任意节点摘除与插入都只需修改常数个指针,因此两种操作都能保持 O(1),而哈希表的 key 指向节点的引用使得"查找 + 移动"可以无需遍历。 ## 完整实现 ```python from typing import Dict, Optional class _Node: """ 手动实现的双向链表节点。 每个节点保存一个键值对,并持有前驱 prev 与后继 next 指针。 使用双向链表(而非单向)是因为删除任意节点时需要访问其前驱, 双向指针可以在 O(1) 内完成摘除操作。 """ __slots__ = ("key", "value", "prev", "next") # 减少内存开销,属性固定 def __init__(self, key: int = 0, value: int = 0): self.key = key self.value = value self.prev: Optional["_Node"] = None self.next: Optional["_Node"] = None class LRUCache: """ LRU 缓存:哈希表 + 双向链表。 数据结构选择原因: - self._map (dict):key -> 节点引用,实现 O(1) 的查找定位。 - 双向链表:维护访问顺序,head 侧为最近使用,tail 侧为最久未使用。 - 使用哨兵头节点 _head 与哨兵尾节点 _tail: 将插入/删除的边界情况统一为普通节点操作,避免对空链表、 单节点链表等情况做额外分支判断,降低出错概率。 """ def __init__(self, capacity: int): if not isinstance(capacity, int) or capacity 节点 # 哨兵节点,不存储有效数据 self._head = _Node() # 头哨兵:其后继为最近使用节点 self._tail = _Node() # 尾哨兵:其前驱为最久未使用节点 self._head.next = self._tail self._tail.prev = self._head # ---------------- 内部辅助方法(均为 O(1)) ---------------- def _remove(self, node: _Node) -> None: """将节点从链表中摘除(不修改哈希表)。""" node.prev.next = node.next node.next.prev = node.prev def _add_to_front(self, node: _Node) -> None: """将节点插入到头哨兵之后,即标记为最近使用。""" node.prev = self._head node.next = self._head.next self._head.next.prev = node self._head.next = node def _move_to_front(self, node: _Node) -> None: """刷新节点的使用顺序:先摘除,再插入头部。""" self._remove(node) self._add_to_front(node) def _pop_lru(self) -> _Node: """淘汰最久未使用的节点(尾哨兵的前驱),并返回该节点。""" lru = self._tail.prev self._remove(lru) return lru # ---------------- 对外接口 ---------------- def get(self, key: int) -> int: """ 获取 key 对应的值。 - 存在:返回值,并将节点移动到链表头部(标记为最近使用)。 - 不存在:返回 -1。 时间复杂度:O(1) """ node = self._map.get(key) if node is None: return -1 self._move_to_front(node) return node.value def put(self, key: int, value: int) -> None: """ 插入或更新键值对。 - key 已存在:更新值并移动到头部。 - key...
AI 评审点评
以下是 AI 评审对该模型输出的点评:
【CLAUDE】这是一份近乎完美的 LRU 缓存实现。设计思路说明简洁到位,准确解释了哈希表 + 双向链表组合的核心优势。代码实现严格遵守所有约束(手动双向链表、无 OrderedDict、O(1) 时间复杂度),哨兵节点设计优雅地消除了边界情况处理。6 个测试用例覆盖全面,通过 __repr__ 验证链表顺序的设计尤为亮点。复杂度分析清晰,额外的 __len__/__contains__/__repr__ 辅助方法提升了类的完整性。该实现在工程质量和算法正确性上均达到了高水准。 【GEMINI】该生成结果堪称范本。严格遵循了所有限制条件(无内置有序结构、手写双向链表),结构设计优雅,代码鲁棒性与可读性极佳,测试覆盖度完备,完全满足所有功能与格式要求。 【KIMI】该实现是LRU缓存的标准优质解法,算法正确、结构清晰、测试充分。哨兵节点设计使代码简洁健壮,复杂度分析准确,完全符合题目所有约束条件。
困难难度评测结果
- 得分:91.8 分
- 通过状态:已通过
模型生成产物
以下是该模型针对此任务的实际生成内容:
# 自适应缓存系统(Adaptive Cache System) ## 1. Design Doc **架构**:`AdaptiveCache` 为门面与调度层,依赖 `CachePolicy` 抽象基类,其子类为 `LRUPolicy`、`LFUPolicy` 和 `ARCPolicy`(骨架)。`HitRateMonitor` 负责滑动窗口统计,`SwitchEvent` 记录切换历史。 **选型**: - LRU 采用「哈希表 + 双向链表」,头部为最久未用,尾部为最近使用,节点移动和摘除均为 O(1)。 - LFU 采用「key→节点哈希 + freq→链表桶哈希 + min_freq 指针」。同频次内按 LRU 决胜,淘汰只需取 min_freq 桶的头节点,为 O(1)。 **切换机制**:窗口记录最近 `window_size` 次 get 的命中结果,并增量维护命中数。每 `check_interval` 次操作且窗口已满时评估一次:LRU 且命中率 high 则切到 LRU。切换时导出当前数据并迁移到新策略,缓存不清空。切换后窗口清零,形成冷却期,以抑制抖动。 ## 2. 完整代码 ```python """ 自适应缓存系统 (Adaptive Cache System) ====================================== 基于滑动窗口命中率,在 LRU 与 LFU 之间自动切换,并预留 ARC 扩展接口。 """ from __future__ import annotations from abc import ABC, abstractmethod from collections import deque from dataclasses import asdict, dataclass from typing import Callable, ClassVar, Deque, Dict, Iterator, List, Optional, Tuple, Type # =========================================================================== # 一、基础数据结构:双向链表节点与链表(LRU / LFU 共用) # =========================================================================== class _ListNode: """双向链表节点。LFU 使用 freq 字段,LRU 忽略该字段。""" __slots__ = ("key", "value", "freq", "prev", "next") def __init__(self, key: int, value: int, freq: int = 1) -> None: self.key: int = key self.value: int = value self.freq: int = freq self.prev: Optional[_ListNode] = None self.next: Optional[_ListNode] = None class _DoublyLinkedList: """带哨兵节点的双向链表。约定:头端为最旧(优先淘汰),尾端为最新。""" def __init__(self) -> None: self._head: _ListNode = _ListNode(-1, -1) self._tail: _ListNode = _ListNode(-1, -1) self._head.next = self._tail self._tail.prev = self._head self._size: int = 0 def __len__(self) -> int: return self._size def push_back(self, node: _ListNode) -> None: """将节点插入尾部。时间复杂度 O(1)。""" last = self._tail.prev assert last is not None node.prev = last node.next = self._tail last.next = node self._tail.prev = node self._size += 1 def remove(self, node: _ListNode) -> None: """摘除链表中的任意节点。时间复杂度 O(1),调用方须保证节点属于本链表。""" assert node.prev...
AI 评审点评
以下是 AI 评审对该模型输出的点评:
【CLAUDE】这是一份高质量的工程实现,完整覆盖了题目的全部要求。算法层面 LRU/LFU 均达到严格 O(1),边界处理细致;系统设计层面分层合理、扩展性强,切换机制含冷却期等工程细节;代码质量层面注解、测试、演示均超出最低要求。整体达到高级工程师水准,无明显缺陷。 【GEMINI】这是一份极高质量的实现。不仅完全满足了题目的各项技术约束(禁止使用 OrderedDict/heapq、O(1) 时间复杂度、面向对象策略模式、ARCPolicy 骨架预留),而且在算法细节与工程鲁棒性上表现优异,测试与演示详尽可信。 【KIMI】该实现整体质量较高,架构设计清晰,代码规范良好,测试覆盖较全面。主要问题集中在LFU算法的min_freq维护存在潜在边界bug,以及export_items使用sorted()导致非严格O(1)。自适应切换机制设计合理,包含防止抖动的冷却期。建议在LFU的min_freq更新逻辑上增加更严谨的边界处理,并考虑将export_items的排序优化或明确标注其复杂度非O(1)。总体而言,这是一个工程化程度较高的实现,但在算法严谨性方面还有提升空间。
相关链接
您可以通过以下链接查看更多相关内容: