Multi-Way Co-Ranking: Index-Space Partitioning of Sorted Sequences Without Merge
Joshi
We present a merge-free algorithm for multi-way co-ranking, the problem of computing cut indices $i_1,\dots,i_m$ that partition each of the $m$ sorted sequences such that all prefix segments together contain exactly $K$ elements. Our method extends two-list co-ranking to arbitrary $m$, maintaining per-sequence bounds that converge to a consistent global frontier without performing any multi-way merge or value-space search. Rather, we apply binary search to \emph{index-space}. The algorithm runs in $O(\log(\sum_t n_t)\,\log m)$ time and $O(m)$ space, independent of $K$. We prove correctness via an exchange argument and discuss applications to distributed fractional knapsack, parallel merge partitioning, and multi-stream joins.
Keywords: Co-ranking \sep partitioning \sep Merge-free algorithms \sep Index-space optimization \sep Selection and merging \sep Data structures
본 논문은 m개의 정렬된 수열을 분할하는 절단 인덱스 i1,…,im을 계산하기 위한 병합 없는 다중 경로 협동 순위 지정 알고리즘을 제안합니다. 모든 전접두사 세그먼트가 정확히 K개의 원소를 포함하도록 합니다. 본 방법은 Siebert와 Träff의 이중 리스트 협동 순위 지정을 임의의 m경로로 확장하며, 각 수열의 경계를 유지하고 다중 경로 병합이나 값 공간 탐색 없이 일관된 전역 전선으로 수렴합니다. 알고리즘은 인덱스 공간에서 이분 탐색을 적용하며, 시간 복잡도는 O(log(∑tnt)logm), 공간 복잡도는 O(m)이며, K와 무관합니다. 교환 논증을 통해 정확성을 증명하고, 분산 분수 배낭, 병렬 병합 분할 및 다중 스트림 조인에서의 응용을 논의합니다.
다중 경로 협동 순위 지정 문제는 다음과 같이 정의됩니다: m개의 비감소 순서로 정렬된 수열 L1,…,Lm(중복 허용), 각 수열의 길이 nt, 그리고 전역 목표 순위 K∈{0,…,N}(여기서 N=∑tnt)가 주어질 때, 다음을 만족하는 절단 인덱스 i1,…,im을 찾아야 합니다:
def multi_way_corank(sequences, K):
m = len(sequences)
# 경계 및 인덱스 초기화
Lb = [0] * m
Ub = [len(seq) for seq in sequences]
i = water_fill_initialization(K, Ub)
# 인덱스 힙 구성
HL = MaxHeap() # 좌측 경계 최대 힙
HR = MinHeap() # 우측 경계 최소 힙
for t in range(m):
HL.insert(t, left_boundary(sequences[t], i[t]))
HR.insert(t, right_boundary(sequences[t], i[t]))
while True:
# 기증자 및 수취자 획득
max_left, p = HL.peek()
min_right, q = HR.peek()
# 종료 조건 확인
if max_left <= min_right:
break
# 이전량 계산
donor_slack = ceil((i[p] - Lb[p]) / 2)
receiver_slack = ceil((Ub[q] - i[q]) / 2)
delta = min(donor_slack, receiver_slack)
# 이전 실행
i[p] -= delta
i[q] += delta
# 경계 업데이트
Ub[p] = i[p]
Lb[q] = i[q]
# 힙 업데이트
update_heaps(HL, HR, sequences, i, p, q)
return i
def water_fill_initialization(K, capacities):
i = [0] * len(capacities)
need = K
for t in range(len(capacities)):
take = min(capacities[t], need)
i[t] = take
need -= take
if need == 0:
break
return i