Sorting algorithms/Quicksort

From Rosetta Code
Revision as of 18:51, 4 October 2008 by 67.35.254.242 (talk) (SML)
Task
Sorting algorithms/Quicksort
You are encouraged to solve this task according to the task description, using any language you may know.

In this task, the goal is to sort an array (or list) of elements using the Quicksort algorithm. The elements must have a strict weak order and the index of the array can be of any discrete type. For languages where this is not possible, sort an array of integers. The algorithm goes like this (from the wiki):

function quicksort(array)
    var list lessOrEqual, greater
    if length(array) ≤ 1  
        return array  
    select a pivot value pivot from array
    for each x in array
        if x ≤ pivot then add x to lessOrEqual
        if x > pivot then add x to greater
    return concatenate(quicksort(lessOrEqual), quicksort(greater))

The "pivot" separates the dataset into two groups: those that are less than or equal to the value at the pivot and those that are greater than the pivot. The Quicksort's worst case time is O(n^2) for a completely sorted set, but otherwise it is O(n * log n). Its average time is slightly faster than that of the merge sort in most cases, even though they are both O(n * log n) sorts.

Ada

This example is implemented as a generic procedure. The procedure specification is: <ada>

-----------------------------------------------------------------------
-- Generic Quicksort procedure
-----------------------------------------------------------------------
generic
    type Element_Type is private;
   type Index_Type is (<>);
   type Element_Array is array(Index_Type range <>) of Element_Type;
   with function "<" (Left, Right : Element_Type) return Boolean is <>; 
   with function ">" (Left, Right : Element_Type) return Boolean is <>;
procedure Sort(Item : in out Element_Array);</ada>

The procedure body deals with any discrete index type, either an integer type or an enumerated type. <ada>

-----------------------------------------------------------------------
-- Generic Quicksort procedure
----------------------------------------------------------------------- 

procedure Sort (Item : in out Element_Array) is
   
   procedure Swap(Left, Right : in out Element_Type) is
      Temp : Element_Type := Left;
   begin
      Left := Right;
      Right := Temp;
   end Swap;
           
   Pivot_Index : Index_Type;
   Pivot_Value : Element_Type;
   Right       : Index_Type := Item'Last;
   Left        : Index_Type := Item'First;
  
begin
   if Item'Length > 1 then
      Pivot_Index := Index_Type'Val((Index_Type'Pos(Item'Last) + 1 + 
                                    Index_Type'Pos(Item'First)) / 2);
      Pivot_Value := Item(Pivot_Index);
      loop
         Left  := Item'First;
         Right := Item'Last;
         while Left < Item'Last and then Item(Left) < Pivot_Value loop
            Left := Index_Type'Succ(Left);
         end loop;
         while Right > Item'First and then Item(Right) > Pivot_Value loop
            Right := Index_Type'Pred(Right);
         end loop;
         exit when Left >= Right;
         Swap(Item(Left), Item(Right));
         if Left < Item'Last and Right > Item'First then
            Left := Index_Type'Succ(Left);
            Right := Index_Type'Pred(Right);
         end if;
      end loop;
      if Right > Item'First then
         Sort(Item(Item'First..Right));
      end if;
      if Left < Item'Last then
         Sort(Item(Left..Item'Last));
      end if;
   end if;
end Sort;</ada>

An example of how this procedure may be used is: <ada>

with Sort;
with Ada.Text_Io;
with Ada.Float_Text_IO; use Ada.Float_Text_IO; 

procedure Sort_Test is
   type Days is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
   type Sales is array(Days range <>) of Float;
   procedure Sort_Days is new Sort(Float, Days, Sales);
   
   procedure Print(Item : Sales) is
   begin
      for I in Item'range loop
         Put(Item => Item(I), Fore => 5, Aft => 2, Exp => 0);
      end loop;
   end Print;
  
   Weekly_Sales : Sales := (Mon => 300.0, 
      Tue => 700.0, 
      Wed => 800.0, 
      Thu => 500.0, 
      Fri => 200.0, 
      Sat => 100.0, 
      Sun => 900.0);
  
begin
  
   Print(Weekly_Sales);
   Ada.Text_Io.New_Line(2);
   Sort_Days(Weekly_Sales);
   Print(Weekly_Sales);
  
end Sort_Test;</ada>

ALGOL 68

From: http://en.wikibooks.org/wiki/Algorithm_implementation/Sorting/Quicksort#ALGOL_68

PROC partition =(REF [] DATA array, PROC (REF DATA, REF DATA) BOOL cmp)INT: (
  INT begin:=LWB array;
  INT end:=UPB array;
  WHILE begin < end DO
     WHILE begin < end DO
      IF cmp(array[begin], array[end]) THEN
        DATA tmp=array[begin];
        array[begin]:=array[end];
        array[end]:=tmp;
        GO TO break while decr end
      FI;
      end -:= 1
     OD;
     break while decr end: SKIP;
     WHILE begin < end DO
      IF cmp(array[begin], array[end]) THEN
        DATA tmp=array[begin];
        array[begin]:=array[end];
        array[end]:=tmp;
        GO TO break while incr begin
      FI;
      begin +:= 1
     OD;
     break while incr begin: SKIP
  OD;
  begin
);

PROC qsort=(REF [] DATA array, PROC (REF DATA, REF DATA) BOOL cmp)VOID: (
  IF LWB array < UPB array THEN
    INT i := partition(array, cmp);
    PAR ( # remove PAR for single threaded sort #
      qsort(array[:i-1], cmp),
      qsort(array[i+1:], cmp)
    )
  FI
);

MODE DATA = INT;
PROC cmp=(REF DATA a,b)BOOL: a>b;

main:(
  []DATA const l=(5,4,3,2,1);
  [UPB const l]DATA l:=const l;
  qsort(l,cmp);
  printf(($g(3)$,l))
)

C

void quick(int *left, int *right)
{
  if (right > left) {
    int pivot = left[(right-left)/2];
    int *r = right, *l = left;
    do {
      while (*l < pivot) l++;
      while (*r > pivot) r--;
      if (l <= r) {
        int t = *l;
        *l++ = *r;
        *r-- = t;
      }
    } while (l <= r);
    quick(left, r);
    quick(l, right);
  }
}
void sort(int *array, int length)
{
  quick(array, array+length-1);
}

C++

The following implements quicksort with a median-of-three pivot. As idiomatic in C++, the argument last is a one-past-end iterator. Note that this code takes advantage of std::partition, which is O(n). Also note that it needs a random-access iterator for efficient calculation of the median-of-three pivot (more exactly, for O(1) calculation of the iterator mid). <cpp>

  1. include <iterator>
  2. include <algorithm> // for std::partition
  3. include <functional> // for std::less

// helper function for median of three template<typename T>

T median(T t1, T t2, T t3)

{

 if (t1 < t2)
 {
   if (t2 < t3)
     return t2;
   else if (t1 < t3)
     return t3;
   else
     return t1;
 }
 else
 {
   if (t1 < t3)
     return t1;
   else if (t2 < t3)
     return t3;
   else
     return t2;
 }

}

// helper object to get <= from < template<typename Order> struct non_strict_op:

 public std::binary_function<typename Order::second_argument_type,
                             typename Order::first_argument_type,
                             bool>

{

 non_strict_op(Order o): order(o) {}
 bool operator()(typename Order::second_argument_type arg1,
                 typename Order::first_argument_type arg2) const
 {
   return !order(arg2, arg1);
 }

private:

 Order order;

};

template<typename Order> non_strict_op<Order> non_strict(Order o) {

 return non_strict_op<Order>(o);

}

template<typename RandomAccessIterator,

        typename Order>
void quicksort(RandomAccessIterator first, RandomAccessIterator last, Order order)

{

 if (first != last && first+1 != last)
 {
   typedef typename std::iterator_traits<RandomAccessIterator>::value_type value_type;
   RandomAccessIterator mid = first + (last - first)/2;
   value_type pivot = median(*first, *mid, *(last-1));
   RandomAccessIterator split1 = std::partition(first, last, std::bind2nd(order, pivot));
   RandomAccessIterator split2 = std::partition(split1, last, std::bind2nd(non_strict(order), pivot));
   quicksort(first, split1, order);
   quicksort(split2, last, order);
 }

}

template<typename RandomAccessIterator>

void quicksort(RandomAccessIterator first, RandomAccessIterator last)

{

 quicksort(first, last, std::less<typename std::iterator_traits<RandomAccessIterator>::value_type>());

} </cpp>

Clojure

A very Haskell-like solution using list comprehensions and lazy evaluation.

 (defn qsort [L]
   (if (nil? L) 
       '()
       (let [[pivot & L2] L]
            (lazy-cat (qsort (for [y L2 :when (<= y pivot)] y))
                      (list pivot)
                      (qsort (for [y L2 :when (> y pivot)] y))))))

D

An implementation much similar to the C one is possible too, this is slower and simpler, derived from the Python one. This is a function template:

import std.stdio;

T[] quickSort(T)(T[] items) {
    T[] less, more;
    if (items.length <= 1)
        return items;
    else {
        T pivot = items[0];
        foreach(el; items[1 .. $])
            if (el < pivot)
                less ~= el;
            else
                more ~= el;
        return quickSort(less) ~ pivot ~ quickSort(more);
    }
}

void main() {
    auto a1 = [4, 65, 2, -31, 0, 99, 2, 83, 782, 1];
    writefln(quickSort(a1));
    auto a2 = [4.0,65.0,2.0,-31.0,0.0,99.0,2.0,83.0,782.0,1.0];
    writefln(quickSort(a2));
}


Erlang

like haskell

qsort([]) -> [];
qsort([X|Xs]) ->
   qsort([ Y || Y <- Xs, Y < X]) ++ [X] ++ qsort([ Y || Y <- Xs, Y >= X]).

Forth

defer lessthan ( a@ b@ -- ? )   ' < is lessthan

: mid ( l r -- mid ) over - 2/ -cell and + ;

: exch ( addr1 addr2 -- ) dup @ >r over @ swap ! r> swap ! ;

: partition ( l r -- l r r2 l2 )
  2dup mid @ >r ( r: pivot )
  2dup begin
    swap begin dup @  r@ lessthan while cell+ repeat
    swap begin r@ over @ lessthan while cell- repeat
    2dup <= if 2dup exch >r cell+ r> cell- then
  2dup > until  r> drop ;

: qsort ( l r -- )
  partition  swap rot
  \ 2over 2over - + < if 2swap then
  2dup < if recurse else 2drop then
  2dup < if recurse else 2drop then ;

: sort ( array len -- )
  dup 2 < if 2drop exit then
  1- cells over + qsort ;

Fortran

Works with: Fortran version 90 and later
MODULE Qsort_Module

IMPLICIT NONE

CONTAINS

RECURSIVE SUBROUTINE Qsort(a)

  INTEGER, INTENT(IN OUT) :: a(:)
  INTEGER :: split

  IF(size(a) > 1) THEN
     CALL Partition(a, split)
     CALL Qsort(a(:split-1))
     CALL Qsort(a(split:))
  END IF
 
END SUBROUTINE Qsort

SUBROUTINE Partition(a, marker)

  INTEGER, INTENT(IN OUT) :: a(:)
  INTEGER, INTENT(OUT) :: marker
  INTEGER :: left, right, pivot, temp
 
  pivot = (a(1) + a(size(a))) / 2  ! Average of first and last elements to prevent quadratic 
  left = 0                         ! behavior with sorted or reverse sorted data
  right = size(a) + 1

  DO WHILE (left < right)
     right = right - 1
     DO WHILE (a(right) > pivot)
        right = right-1
     END DO
     left = left + 1
     DO WHILE (a(left) < pivot)
        left = left + 1
     END DO
     IF (left < right) THEN 
        temp = a(left)
        a(left) = a(right)
        a(right) = temp
     END IF
  END DO

  IF (left == right) THEN
     marker = left + 1
  ELSE
     marker = left
  END IF

END SUBROUTINE Partition

END MODULE Qsort_Module

PROGRAM Quicksort

  USE Qsort_Module
 
  IMPLICIT NONE
  INTEGER, PARAMETER :: n = 100
  INTEGER :: array(n)
  INTEGER :: i
  REAL :: x

  CALL RANDOM_SEED
  DO i = 1, n
     CALL RANDOM_NUMBER(x)
     array(i) = INT(x * 10000)
  END DO
 
  WRITE (*, "(A)") "array is :-"
  WRITE (*, "(10I5)") array
  CALL Qsort(array)
  WRITE (*,*)
  WRITE (*, "(A)") "sorted array is :-"  
  WRITE (*,"(10I5)") array
  
END PROGRAM Quicksort

Haskell

The famous two-liner, reflecting the underlying algorithm directly:

qsort []     = []
qsort (x:xs) = qsort [y | y <- xs, y <= x] ++ [x] ++ qsort [y | y <- xs, y > x]

A more efficient version, doing only one comparison per element:

import Data.List

qsort [] = []
qsort (x:xs) = qsort ys ++ x : qsort zs where (ys, zs) = partition (<= x) xs

IDL

IDL has a powerful optimized sort() built-in. The following is thus merely for demonstration.

function qs, arr
  if (count = n_elements(arr)) lt 2 then return,arr
  pivot = total(arr) / count ; use the average for want of a better choice
  return,[qs(arr[where(arr le pivot)]),qs(arr[where(arr gt pivot)])]
 end

Example:

IDL> print,qs([3,17,-5,12,99])
     -5       3      12      17      99

J

sel=: 1 : 'x # ['

quicksort=: 3 : 0
 if. 1 >: #y do. y else. (quicksort y <sel e),(y =sel e),quicksort y >sel e=.y{~?#y end.
)

To actually sort data in J, it is more convenient and more efficient to use /:~ .

Java

Works with: Java version 1.5+
Translation of: Python

<java>public static <E extends Comparable<? super E>> LinkedList<E> quickSort(LinkedList<E> arr){ LinkedList<E> less= new LinkedList<E>(); LinkedList<E> pivotList= new LinkedList<E>(); LinkedList<E> more= new LinkedList<E>(); if(arr.size() <= 1) return arr; E pivot= arr.getFirst(); //This pivot can change to get faster results for(E i: arr){ if(i.compareTo(pivot)<0) less.add(i); else if(i.compareTo(pivot)>0) more.add(i); else pivotList.add(i); } less= quickSort(less); more= quickSort(more); less.addAll(pivotList); less.addAll(more); return less; }</java>

JavaScript

<javascript>function sort(a,less) {

 function swap(i,j) { var t=a[i]; a[i]=a[j]; a[j]=t }
 function qs(l,r) {
   if (l<r) {
     var pivot = a[(l+r)>>1];
     var l2=l, r2=r;
     do {
       while (less(a[l2], pivot) ++l2;
       while (less(pivot, a[r2]) --r2;
       if (l2 <= r2) swap(l2++, r2--);
     } while (l2 <= r2);
     qs(l, r2);
     qs(l2, r);
   }
 }
 qs(0, a.length-1);
 return a;

}</javascript>

Joy

DEFINE qsort ==
   [small]
   []
   [uncons [>] split]
   [[swap] dip cons concat]
   binrec .

Lucid

[1]

qsort(a) = if eof(first a) then a else follow(qsort(b0),qsort(b1)) fi
 where
    p = first a < a;
    b0 = a whenever p;
    b1 = a whenever not p;
    follow(x,y) = if xdone then y upon xdone else x fi
                    where
                       xdone = iseod x fby xdone or iseod x; 
                    end;
 end

MAXScript

fn quickSort arr =
(
    less = #()
    pivotList = #()
    more = #()
    if arr.count <= 1 then
    (
        arr
    )
    else
    (
        pivot = arr[arr.count/2]
        for i in arr do
        (
            case of
            (
                (i < pivot):	(append less i)
                (i == pivot):	(append pivotList i)
                (i > pivot):	(append more i)
            )
        )
        less = quickSort less
        more = quickSort more
        less + pivotList + more
    )
)
a = #(4, 89, -3, 42, 5, 0, 2, 889)
a = quickSort a

Nial

quicksort is fork [ >= [1 first,tally],
  pass,
  link [
      quicksort sublist [ < [pass, first], pass ],
      sublist [ match [pass,first],pass ],
      quicksort sublist [ > [pass,first], pass ]
  ]
]

Using it.

|quicksort [5, 8, 7, 4, 3]
=3 4 5 7 8

OCaml

let rec quicksort gt = function
  | [] -> []
  | x::xs ->
      let ys, zs = List.partition (gt x) xs in
        quicksort gt ys @ x :: quicksort gt zs

let _ =
  quicksort (>) [4; 65; 2; -31; 0; 99; 83; 782; 1]

Perl

sub quick_sort {
  $arr = shift;
  local $less = [];
  local $pivot_list = [];
  local $more = [];
  if ($#{$arr} <= 0) {
    return $arr;
  } else {
    $pivot = $arr->[0];
    foreach my $i (@{$arr}) {
      if ($i < $pivot) {
        push @{$less}, $i;
      } elsif ($i > $pivot) {
        push @{$more}, $i;
      } else {
        push @{$pivot_list}, $i;
      }
    }
    $less = quick_sort($less);
    $more = quick_sort($more);
    return [@{$less}, @{$pivot_list}, @{$more}];
  }
}

print join(' ', @{quick_sort([4, 65, 2, -31, 0, 99, 83, 782, 1])}), "\n";

Output:

-31 0 1 2 4 65 83 99 782

Python

def quickSort(arr):
    less = []
    pivotList = []
    more = []
    if len(arr) <= 1:
        return arr
    else:
        pivot = arr[0]
        for i in arr:
            if i < pivot:
                less.append(i)
            elif i > pivot:
                more.append(i)
            else:
                pivotList.append(i)
        less = quickSort(less)
        more = quickSort(more)
        return less + pivotList + more

a = [4, 65, 2, -31, 0, 99, 83, 782, 1]
a = quickSort(a)

In a Haskell fashion: <python> def qsort(L):

   return (qsort([y for y in L[1:] if y <= L[0]]) + 
           L[:1] + 
           qsort([y for y in L[1:] if y >  L[0]])) if len(L) > 1 else L

</python>

Scheme

(define (split-by l p)
  (let loop ((low (list)) (high (list)) (l l))
    (if (null? l)
        (cons low high)
        (if (p (car l))
            (loop low (cons (car l) high) (cdr l))
            (loop (cons (car l) low) high (cdr l))))))

(define (quicksort l gt?)
  (let q ((l l))
    (if (null? l)
        l
        (let ((s (split-by (cdr l) (lambda (x) (gt? x (car l))))))
          (append (q (car s)) (list (car l)) (q (cdr s)))))))
(quicksort (list 1 3 5 7 9 8 6 4 2) >)

Seed7

const proc: quickSort (inout array elemType: arr, in integer: left, in integer: right) is func
  local
    var elemType: compare_elem is elemType.value;
    var integer: less_idx is 0;
    var integer: greater_idx is 0;
    var elemType: help is elemType.value;
  begin
    if right > left then
      compare_elem := arr[right];
      less_idx := pred(left);
      greater_idx := right;
      repeat
        repeat
          incr(less_idx);
        until arr[less_idx] >= compare_elem;
        repeat
          decr(greater_idx);
        until arr[greater_idx] <= compare_elem or greater_idx = left;
        if less_idx < greater_idx then
          help := arr[less_idx];
          arr[less_idx] := arr[greater_idx];
          arr[greater_idx] := help;
        end if;
      until less_idx >= greater_idx;
      arr[right] := arr[less_idx];
      arr[less_idx] := compare_elem;
      quickSort(arr, left, pred(less_idx));
      quickSort(arr, succ(less_idx), right);
    end if;
  end func;

const proc: quickSort (inout array elemType: arr) is func
  begin
    quickSort(arr, 1, length(arr));
  end func;

Original source: [2]

SML

fun quicksort nil : int list = nil
  | quicksort (x::xs) =
    let 
        val part = List.partition (fn y => y<x) xs
	val left = #1 part
        val right = #2 part
    in
	quicksort left @ [x] @ quicksort right
    end

UnixPipes

Works with: Zsh
split() {
  (while read n ; do
      test $1 -gt $n && echo $n > $2 || echo $n > $3
  done)
}
qsort() {
 (read p; test -n "$p" && (
     lc="1.$1" ; gc="2.$1"
     split $p >(qsort $lc >$lc) >(qsort $gc >$gc);
     cat $lc <(echo $p) $gc
     rm -f $lc $gc;
 ))
}
cat to.sort | qsort

V

[qsort
  [joinparts [p [*l1] [*l2] : [*l1 p *l2]] view].
  [split_on_first uncons [>] split].
  [small?]
    []
    [split_on_first [l1 l2 : [l1 qsort l2 qsort joinparts]] view i]
  ifte].

The way of joy (using binrec)

[qsort
   [small?] []
     [uncons [>] split]
     [[p [*l] [*g] : [*l p *g]] view]
   binrec].