PrepStack · Markdown HTML

K 路归并堆

堆、选择与流 · HTML

数学 / 逻辑形态

有 m 个非降序序列 S_j。堆保存每个非空来源的最前未消费项 (value,j,pos)。每次弹出全局最小项,仅把同一来源的下一项加入。

识别信号

容易误判的相似信号

SignalWhy it is different
来源内部无序仅看头部无法保证全局最小;先排序各来源或改用普通选择结构。
一般图最短路Dijkstra 会松弛共享状态并处理多条到达路径;K 路归并的来源是固定、互不汇合的有序链。
只有两个内存数组双指针归并 O(N) 且常数更小,无需堆。

核心不变量

对每个仍有剩余元素的来源,堆中恰有其最前未消费项;所有未输出元素的全局最小值必在堆中。

状态、转移与处理顺序

ItemDefinition
State大小至多 m 的小根堆,entry 为 (值/键, 来源编号, 来源内位置)。
Transition弹出一个头部作为下一输出,推进它所属来源一格;未耗尽则加入新头部。
Frontier / orderm 条有序链的头部集合;每次只扩展刚胜出的来源。

Python 骨架

from heapq import heappop, heappush

def merge_sorted(sources):
    heap = []
    for sid, seq in enumerate(sources):
        if seq:
            heappush(heap, (seq[0], sid, 0))
    out = []
    while heap:
        value, sid, pos = heappop(heap)
        out.append(value)
        pos += 1
        if pos < len(sources[sid]):
            heappush(heap, (sources[sid][pos], sid, pos))
    return out

正确性思路

  1. 每个来源未消费部分的最小值就是其头部。
  2. 全体未消费元素的最小值因此等于所有来源头部的最小值,heap pop 的下一输出正确。
  3. 弹出后只有胜出来源失去头部;推进它就恢复不变量。

复杂度

TimeSpaceParameters
输出 N 项 O(N log m);只取 t 项为 O(m+t log m)O(m),不计输出m 为来源数,N 为总项数,t 为实际消费数。

边界条件

错误模式

PatternWhy it fails / fix
把整个来源压入堆空间膨胀到 O(N),失去只保留 m 个前沿的价值。
推进所有来源只有胜出来源失去头部;推进其他来源会跳过尚未输出项。
entry 不含来源身份弹出后不知道推进哪条链;必须携带来源和位置/迭代器。

选择与排除规则

相关模板

RelationTemplateBoundary
composition链表指针改线归并链表时,堆选择、指针改线负责拼接。
contrastTop-K 有界堆Top-K 淘汰候选;K 路归并保留每个来源的下一项。

原创微型例子

环节内容
Result得到 [1,2,3,5,7,8],堆从未超过 3 项。
Setup三条时间流为 [1,8]、[2,3]、[5,7]。
Trace头部 1,2,5 入堆;弹 1 后只加 8,随后弹 2、3、5、7、8。

Recall prompts

我的补充