Quick sort with erlang, elixir, python
Wikipedia article about merge sort algorithm.
Source code examples on Github
Erlang implementation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/bin/env escript %% -*- erlang -*- %%! -smp enable -sname p9 % vim:syn=erlang -mode(compile). main(_) -> {A,B,C} = erlang:timestamp(), random:seed(A,B,C), L = [random:uniform(10000)||_<-lists:seq(1,5000000)], {T,_L1} = timer:tc(fun()->qs(L) end), io:format("Done ~p ~n", [T/1000000]). % %------------------ QUICKSORT ---------------------- qs([]) -> []; qs([H|T]) -> qs([E||E<-T, E<H]) ++ [H] ++ qs([E||E<-T, H =< E]). |
Almost same things with elixir:
1 2 3 4 5 6 7 8 9 10 11 | defmodule Sort do def qs([]), do: [] def qs([h|t]) do l = for x <- t, x < h, do: x r = for x <- t, x >= h, do: x qs(l) ++ [h] ++ qs(r) end end |
and python implementation also with using list comprehensions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/python3 import random from timeit import default_timer as timer def qs(l): if len(l) == 0: return [] return qs([x for x in l[1:] if x < l[0]]) + [l[0]] + qs([x for x in l[1:] if x >= l[0]]) l = [random.randint(1,10000) for _ in range(1,5000000)] start=timer() l1 = qs(l) end=timer() print("Done: %s" % str(end - start)) |
Erlang implementation of quicksort can be easily changed to distributed implementation. Implementation below using same erlang node and number of processes equal processor cores, but it can spawn new processes on different erlang nodes and different machines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #!/usr/bin/env escript %% -*- erlang -*- %%! -smp enable -sname p9 % vim:syn=erlang -mode(compile). main(_) -> {A,B,C} = erlang:timestamp(), random:seed(A,B,C), L = [random:uniform(10000)||_<-lists:seq(1,5000000)], %io:format("Merge sort list: ~p ~n", [L]), %io:format("Merge sort list: ~p ~n", [qs(L, erlang:system_info(schedulers) )]). {T,_} = timer:tc(fun()->qs(L, erlang:system_info(schedulers)) end), io:format("Done ~p ~n", [T/1000000]). % % ---------- distributed quicsort algorithm -------- qs([],_) -> []; qs([H|T], N) when N > 1 -> {Parent, Ref} = {self(), make_ref()}, spawn(fun()-> Parent ! {l1, Ref, qs([E||E<-T, E<H], N-2)} end), spawn(fun()-> Parent ! {l2, Ref, qs([E||E<-T, H =< E], N-2)} end), {L1, L2} = receive_results(Ref, undefined, undefined), L1 ++ [H] ++ L2; qs([H|T],_) -> qs([E||E<-T, E<H],0) ++ [H] ++ qs([E||E<-T, H =< E],0). receive_results(Ref, L1, L2) -> receive {l1, Ref, L1R} when L2 == undefined -> receive_results(Ref, L1R, L2); {l2, Ref, L2R} when L1 == undefined -> receive_results(Ref, L1, L2R); {l1, Ref, L1R} -> {L1R, L2}; {l2, Ref, L2R} -> {L1, L2R} after 5000 -> receive_results(Ref, L1, L2) end. |
Some speed measurements:
1 2 3 4 5 6 | vagrant@mblog:~/pr_euler/algorithms/quicksort$ ./qs1.erl Done 20.498445 vagrant@mblog:~/pr_euler/algorithms/quicksort$ ./qs2.erl Done 15.467243 ivagrant@mblog:~/pr_euler/algorithms/quicksort$ ./qs1.py Done: 192.65369251003722 |
Looks like recursion and list comprehensions in Python much slower Erlang.