“在不知道具体块大小 $B$ 与缓存容量 $M$、但采用理想缓存假设时,Funnel Sort以递归漏斗归并实现 cache oblivious 比较排序,并达到排序 I/O 界所要求的渐近扫…”
形式陈述 ​
要解决的不是比较次数 ​
Funnel Sort 是缓存无关模型中的比较排序。输入
它的目标 I/O 界是
当
k-merger 的接口 ​
一个
Funnel 把二路 merger 组织成递归网络,并在中间边上放置不同容量的缓冲。下层 merger 只在上游缓冲需要补充时才运行,一次填入一批连续记录。缓冲大小随所连接子漏斗的规模增长,使一棵能放入缓存的子漏斗在生产大量输出期间无需频繁重新装入。
正确性不变量很简单:每条内部边上的缓冲保持有序,每个 merger 只比较两个输入缓冲的当前首项。因此从根输出的下一项是所有尚未输出记录中的最小者。复杂度的难点不在这个次序证明,而在选择递归形状和缓冲容量。
排序递归 ​
当
指数
直觉
Funnel Sort 用递归网络在许多未知缓存尺度上同时形成多路归并。靠近叶子的缓冲吸收细粒度输入,靠近根的较大缓冲成批供应全局最小前沿;当某个子漏斗恰能驻留缓存时,它可以连续生产大量输出,成本便按整块摊到记录上。
例子与边界
八条短流如何穿过漏斗 ​
设有八条排序流,首项依次为
底层四个二路 merger 先把相邻流的小批量前缀写入四个缓冲;中层两个 merger 再各自按需填充更大的输出缓冲;根只比较这两个中层缓冲的首项。根先输出 1,随后补充该路径上的空槽,而不会扫描其余七条流。
若含 1 的输入下一项为 20,根接下来看到的全局最小值是 4。此时其他支路已经把 4、6 等候选顺序放在靠近根的缓冲里;磁盘上的长尾并未因每个输出而随机访问。一个缓冲耗尽时才触发 refill,refill 产生一段而非一个记录。
这个例子说明批量填充的方向,却不以八条流证明渐近界。真正分析在某个递归子漏斗首次能装入
I/O 分析的分层尺度 ​
固定实际
记录从叶流到根要跨越
个有效尺度,每个尺度总代价
失败边界与实现条件 ​
缓存替换按 ideal-cache 的最优策略分析。真实 LRU、组相联缓存和预取器可能改变常数;“cache-oblivious”表示代码不调参,不表示物理存储没有块或任意替换策略都保留同一证明。
记录若为可变长对象,
普通归并排序的二路扫描每一层都顺序,但仍有
推论与应用
该算法证明缓存无关设计也能达到比较外存排序的最优 I/O 量级,并可由同一代码适配多级缓存。它更适合作为递归布局与缓冲分析的范型;实际实现若更重视常数、SIMD 或显式设备参数,已知
参考资料
- Matteo Frigo, Charles E. Leiserson, Harald Prokop and Sridhar Ramachandran, Cache-Oblivious Algorithms, ACM Transactions on Algorithms, 2012.
- Harald Prokop, Cache-Oblivious Algorithms, MIT Master's Thesis, 1999.
- Jeffrey Scott Vitter, Algorithms and Data Structures for External Memory, Foundations and Trends in Theoretical Computer Science, 2008.