DMarlon Studio

Lesson 17 · 17 of 20

Quicksort and binary search · Pascal

Write quicksort and binary search in Pascal with open arrays and recursion, and see why searching a sorted list is so fast.

Pascal · Quicksort and binary search in DMarlon Studio: the example's code and its output in the terminal

Quicksort sorts by picking a pivot and moving smaller values to its left and larger ones to its right; then it does the same to each side. This version (the Lomuto partition) uses the last element, a[hi], as the pivot.

The variable i marks the boundary of the smaller values: the for loop walks the range and, whenever it finds a value below the pivot, swaps it with a[i] and moves the boundary on. At the end, the pivot goes into a[i], which is already its final place, and the two recursive calls sort each side if it has more than one element.

The var a: array of Integer parameter is an open array: it accepts arrays of any size and, being var, sorts them in place. The codes array is declared with its values already in it, which Free Pascal 3.2 also allows for dynamic arrays. On average quicksort makes about n·log n comparisons; in the worst case, with already sorted data and this pivot, it reaches n².

Binary search only works on sorted data: it looks at the middle element and discards the half where the target cannot be. Find does it recursively and returns -1 with Exit(-1) once the range is empty. With a million codes, about 20 comparisons are enough.

Code · main.pas

program main;procedure QuickSort(var a: array of Integer; lo, hi: Integer);var i, j, tmp: Integer;begin  i := lo;  for j := lo to hi - 1 do    if a[j] < a[hi] then  // a[hi] is the pivot    begin      tmp := a[i]; a[i] := a[j]; a[j] := tmp;      Inc(i);    end;  tmp := a[i]; a[i] := a[hi]; a[hi] := tmp;    // the pivot to its final place  if lo < i - 1 then QuickSort(a, lo, i - 1);  // smaller values, on the left  if i + 1 < hi then QuickSort(a, i + 1, hi);  // bigger ones, on the rightend;function Find(const a: array of Integer; target, lo, hi: Integer): Integer;var mid: Integer;begin  if lo > hi then Exit(-1);  // nothing left to look at  mid := (lo + hi) div 2;  if a[mid] = target then Result := mid  else if a[mid] < target then Result := Find(a, target, mid + 1, hi)  else Result := Find(a, target, lo, mid - 1);end;var  codes: array of Integer = (4021, 1187, 9350, 2764, 5512, 3308, 7045);  code: Integer;begin  QuickSort(codes, 0, High(codes));  for code in codes do Write(code, ' ');  WriteLn(LineEnding, '5512 is at index ', Find(codes, 5512, 0, High(codes)));  WriteLn('6000 is at index ', Find(codes, 6000, 0, High(codes)));end.

Output · fpc main.pas && ./main

1187 2764 3308 4021 5512 7045 9350 
5512 is at index 4
6000 is at index -1

Key points

  • Quicksort: partition around a pivot and sort each side.
  • After partitioning, the pivot is already in its final place.
  • var a: array of Integer accepts arrays of any size.
  • Binary search needs sorted data.
  • Each step of binary search throws away half.

Exercise

Change QuickSort's comparison to sort from largest to smallest, and adapt Find so it still works with that order.