Вот решение (слегка приглушенное), которое должно работать с массивами любых коллекций типа списка, которые поддерживают #first
, #shift
и #empty?
.Обратите внимание, что это разрушительно - каждый вызов lazymerge
удаляет один элемент из одной коллекции.
def minheap a,i
r=(l=2*(m=i)+1)+1 #get l,r index
m = l if l< a.size and a[l].first < a[m].first
m = r if r< a.size and a[r].first < a[m].first
(a[i],a[m]=a[m],a[i];minheap(a,m)) if (m!=i)
end
def lazymerge a
(a.size/2).downto(1){|i|minheap(a,i)}
r = a[0].shift
a[0]=a.pop if a[0].empty?
return r
end
p arrs = [ [1,2,3], [2,4,5], [4,5,6],[3,4,5]]
v=true
puts "Extracted #{v=lazymerge (arrs)}. Arr= #{arrs.inspect}" while v
Вывод:
[[1, 2, 3], [2, 4, 5], [4, 5, 6], [3, 4, 5]]
Extracted 1. Arr= [[2, 3], [2, 4, 5], [4, 5, 6], [3, 4, 5]]
Extracted 2. Arr= [[3], [2, 4, 5], [4, 5, 6], [3, 4, 5]]
Extracted 2. Arr= [[4, 5], [3], [4, 5, 6], [3, 4, 5]]
Extracted 3. Arr= [[4, 5], [3, 4, 5], [4, 5, 6]]
Extracted 3. Arr= [[4, 5], [4, 5], [4, 5, 6]]
Extracted 4. Arr= [[5], [4, 5], [4, 5, 6]]
Extracted 4. Arr= [[5], [5], [4, 5, 6]]
Extracted 4. Arr= [[5, 6], [5], [5]]
Extracted 5. Arr= [[6], [5], [5]]
Extracted 5. Arr= [[5], [6]]
Extracted 5. Arr= [[6]]
Extracted 6. Arr= [[]]
Extracted . Arr= [[]]
Обратите также внимание, что этот алгоритм также ленив о поддержании свойства кучи - он не поддерживается между вызовами.Это, вероятно, заставляет его выполнять больше работы, чем необходимо, поскольку он выполняет полную кучи при каждом последующем вызове.Это можно исправить, выполнив полную кучу один раз, затем вызвав minheap(a,0)
перед строкой return r
.