Implement an algorithm to merge an arbitrary number of sorted lists into one sorted list. The aim is to create the smallest working programme, in whatever language you like.
Ruby:
41 significant chars, 3 significant whitespace chars in the body of the merge method.
arrs is an array of arrays
def merge_sort(arrs)
o = Array.new
arrs.each do |a|
o = o | a
end
o.sort!
end
To test in irb:
arrs = [ [ 90, 4, -2 ], [ 5, 6, -100 ], [ 5, 7, 2 ] ]
merge_sort(arrs)
Returns: [-100, -2, 2, 4, 5, 6, 7, 90]
Edit: Used the language provided merge/sort because it is likely backed by C code and meets the 'faster' requirement. I'll think about the solution without later (it's the weekend here and I am on holiday).
Implementation in C via Linked lists.
http://datastructuresandalgorithmsolutions.blogspot.com/2010/02/chapter-2-basic-abstract-data-types_7147.html
Python: 113 characters
def m(c,l):
try:
c += [l[min((m[0], i) for i,m in enumerate(l) if m)[1]].pop(0)]
return m(c,l)
except:
return c
# called as:
>>> m([], [[1,4], [2,6], [3,5]])
[1, 2, 3, 4, 5, 6]
EDIT: seeing as talk of performance has come up in a few places, I'll mention that I think this is pretty efficient implementation, especially as the lists grow. I ran three algorithms on 10 lists of sorted random numbers:
sorted(sum(lists, []))
(Built-in)EDIT2: (JFS)
The figure's labels:
merge_26
-- heapq.merge()
from Python 2.6 stdlib merge_alabaster
-- the above code (labeled Merge
on the above figure)sort_builtin
-- L = sum(lists,[]); L.sort()
Input data are [f(N) for _ in range(10)]
, where f()
is:
max_ = 2**31-1
def f(N):
L = random.sample(xrange(max_), n)
L.sort()
return L
f.__name__ = "sorted_random_%d" % max_
NOTE: merge_alabaster()
doesn't work for N > 100
due to RuntimeError: "maximum recursion depth exceeded"
.
To get Python scripts that generated this figure, type:
$ git clone git://gist.github.com/51074.git
Conclusion: For reasonably large lists the built-in sort shows near linear behaviour and it is the fastest.
C#
static void f(params int[][] b)
{
var l = new List<int>();
foreach(var a in b)l.AddRange(a);
l.OrderBy(i=>i).ToList().ForEach(Console.WriteLine);
}
static void Main()
{
f(new int[] { 1, 4, 7 },
new int[] { 2, 5, 8 },
new int[] { 3, 6, 9 });
}
Haskell: 127 characters (without indentation and newlines)
m l|all null l=[]
|True=x:(m$a++(xs:b))
where
n=filter(not.null)l
(_,min)=minimum$zip(map head n)[0..]
(a,((x:xs):b))=splitAt min n
It basically generalizes the merging of two lists.
Python, 181 chars
from heapq import *
def m(l):
r=[]
h=[]
for x in l:
if x:
heappush(h, (x[0], x[1:]))
while h:
e,f=heappop(h)
r.append(e)
if f:
heappush(h, (f.pop(0),f))
return r
This runs in O(NlgM) time, where N is the total number of items and M is the number of lists.