“Misra–Gries 为频繁项与重项问题处理insertion only 流 $a 1,\ldots,a m$,取整数 $k\ge2$,用一个至多含 $k 1$ 个键的字典维护候选及计数:…”
形式陈述
给定键域
其定义域 lookup(k) 在 contains(k) 判断这一成员关系;insert(k,v) 或 update(k,v) 产生满足 delete(k) 移除 iterate() 恰好枚举当前所有键值对,但除非规格另有声明,不承诺顺序。可变接口把这些函数关系实现为状态转移,不改变其可观察语义。
集合 ADT 是该规格的退化情形:只记录键是否存在,可把值域取为单位类型
直觉
抽象数据类型先规定用户能够观察什么,再把存储方法留给实现。对 map,核心事实不是桶、指针或树高,而是每个当前键至多有一个现行值,以及每次操作如何改变这张有限对应表。哈希表可以放弃顺序换取期望常数时间,平衡搜索树可以维护键序支持范围查询;只要查询和更新遵守同一契约、迭代返回规范允许的某个次序,它们就能实现同一个基本 ADT;无需让每次迭代的输出序列逐项相同。
这种分层也解释了为什么复杂度不能偷偷写进定义。lookup 的语义是返回对应值或缺失,并不自动意味着
例子与边界
设初始映射为空,依次执行 insert("Ada", 36)、insert("Lin", 41)、insert("Ada", 37)。普通 map 的最终状态为
同一状态用哈希表迭代可能先返回 Lin,也可能先返回 Ada;有序 map 则按键比较次序输出。这一差异不影响 lookup,却会影响序列化和可复现实验,因此“迭代次序”必须作为额外契约明确加入,不能从 map 一词推断。集合接口同样只保证成员语义;数学集合可以无限,而实际数据结构在任一有限时刻只表示有限个已存元素。
空映射上的 delete(k) 可规定为无操作,也可返回“键不存在”的错误;两种设计都能自洽,但不能在实现之间无声切换。键的相等关系和可变性也属于边界:若键插入后其哈希值或比较结果改变,具体结构可能再也找不到它,即使抽象状态原本仍含该键。
推论与应用
实现应按操作组合和存储层选择。二叉搜索树提供有序字典的基本比较模型,红黑树把查找、插入和删除都约束在最坏
哈希表、搜索树和 trie 都可以实现字典;集合去重、符号表、缓存索引、数据库主键表则共享同一组成员与更新语义。算法分析应先用 lookup、insert、delete 等抽象操作证明正确性,再代入所选实现的最坏、摊还或期望成本。这样更换实现只改变性能论证,不会连带改写算法含义。
把值域换成计数器可得到频率表,换成对象列表可得到倒排索引;这些仍是普通 map,只是值类型更丰富。真正允许一个键拥有多个独立关联、且分别插删关联时,才需要 multimap 的另一套操作规格。
把同一接口交给两个表示检查
要比较两个实现,先把返回值也写进小规格。配套字典契约实验采用 put(k,v) 覆盖旧值并返回空结果,get(k) 返回 (found,value),delete(k) 返回删除前的同一对结果,缺失删除不改变映射。found 单独存在,因而“键存在且值为 None”与“键缺失”不会混淆。重建只改变表示,抽象映射与键数都保持不变。迭代只比较键值对,不要求链桶顺序等于槽位顺序。
实验让一份独立的 Python dict 只执行这些抽象转移。链地址表和线性探测表各执行同一条操作历史,每步同时核对返回值、活动记录和表示不变量。抽象检查器不调用被测实现的 get 来拼出期望答案,也不复用它的停止规则;否则,一个错误查询可能同时污染“实际结果”和所谓标准答案。
检查的次序很重要。先确认物理记录中没有重复键,再把它们解释成映射。若两个槽都保存 (3,b),直接调用 dict(records) 会把它们折叠成一项,甚至与正确抽象状态完全相同;物理唯一性却已经失败,下一次删除一个副本可能让旧值重新出现。实验专门注入“遇墓碑立即插入”的错误,让这个原本会被抽象化掩盖的问题在第四步被抓住。
这些检查是实现精化的有限证据。推广到任意历史仍需证明:初始表示合法;每个公开操作保持表示不变量,并与抽象转移相符。测试提供具体失败状态,归纳证明负责覆盖没有列举的长度与键值。MIT 6.031 的抽象函数与表示不变量给出了这一分工的基础。
参考资料
- Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms, 4th ed., MIT Press, 2022, Ch. 11, dictionaries and hash tables.
- Robert Sedgewick and Kevin Wayne, Algorithms, 4th ed., Addison-Wesley, 2011, Ch. 3, symbol tables.