Heapsort and Quicksort Overview
Heapsort and Quicksort Overview
Werner Nutt
Acknowledgments
• The course follows the book “Introduction to Algorithms‘”,
by Cormen, Leiserson, Rivest and Stein, MIT Press
[CLRST]. Many examples displayed in these slides are
taken from their book.
• These slides are based on those developed by
Michael Böhlen for this course.
(See [Link]
• The slides also include a number of additions made by
Roberto Sebastiani and Kurt Ranalter when they taught
later editions of this course
(See [Link]
●
About sorting algorithms
●
Heapsort
– complete binary trees
– heap data structure
• Quicksort
– a popular algorithm
– very fast on average
●
About sorting algorithms
●
Heapsort
– Complete binary trees
– Heap data structure
• Quicksort
– a popular algorithm
– very fast on average
Why Sorting?
• “When in doubt, sort” –
one of the principles of algorithm design.
Why Sorting?/2
• Merge sort
– Worst-case running time Θ(n log n)
– Requires additional memory Θ(n)
●
About sorting algorithms
●
Heapsort
– Complete binary trees
– Heap data structure
• Quicksort
– a popular algorithm
– very fast on average
Selection Sort
SelectionSort(A[1..n]):
SelectionSort(A[1..n]):
for ii (*
for (* 11 to
to n-1
n-1
A:
A: Find
Find the
the smallest
smallest element
element among
among A[i..n]
A[i..n]
B:
B: Exchange
Exchange it it with
with A[i]
A[i]
Binary Trees
Binary Trees/2
Binary Trees/3
Heaps
• A binary tree is a binary heap iff
– it is a nearly complete binary tree
– each node is greater than or equal to all its children
• The properties of a binary heap allow
– an efficient storage as an array (because it is a nearly
complete binary tree)
– a fast sorting (because of the organization of the
values)
Heaps/2
3
1
Heap property 16
2 3
A[Parent(i)] ≥ A[i] 15 10
4 5 6 7
8 7 9 3
Parent(i) 8 9 10
return ⌊i/2⌋ 2 4 1
Left(i)
return 2i 1 2 3 4 5 6 7 8 9 10
16 15 10 8 7 9 3 2 4 1
Right(i) Level: 0 1 2 3
return 2i+1
Master Informatique Data Structures and Algorithms
15
Chapter
4 Sor4ng:
Heapsort
and
Quicksort
Heaps/3
• Notice the implicit tree links in the array:
children of node i are 2i and 2i+1
• The heap data structure can be used to implement a fast
sorting algorithm.
• The basic elements are
– Heapify: reconstructs a heap after an element was
modified
– BuildHeap: constructs a heap from an array
– HeapSort: the sorting algorithm
Heapify
• Input: index i in array A, number n of elements
• Binary trees rooted at Left(i) and Right(i) are heaps
• A[i] might be smaller than its children, thus violating the
heap property.
• Heapify makes A a heap by moving A[i] down the heap
until the heap property is satisfied again.
Heapify Example
1
1
2
16 16
3
2 3
4 10
4 5 6 7 14 10
4 5 6 7
14 7 9 3
8 9 10
8 7 9 3
8 9 10
2 8 1
1 2 4 1
16
2 3
14 10 [Link] Heapify(A,2)
4 5 6 7 [Link] A[2] with A[4] and
4 7 9 3 recursively call Heapify(A,4)
8 9 10 [Link] A[4] with A[9] and
2 8 1 recursively call Heapify(A,9)
[Link] 9 has no children,
so we are done
Master Informatique Data Structures and Algorithms
18
Chapter
4 Sor4ng:
Heapsort
and
Quicksort
Heapify Algorithm
Heapify(A,i,n)
Heapify(A,i,n)
ll :=
:= 2*i;
2*i; //
// ll :=
:= Left(i)
Left(i)
rr :=
:= 2*i+1;
2*i+1; //// rr :=
:= Right(i)
Right(i)
if
if ll <=
<= nn and
and A[l]
A[l] >> A[i]
A[i]
then
then maxpos
maxpos :=:= ll
else
else maxpos
maxpos :=:= ii
if
if rr <=
<= nn and
and A[r]
A[r] >> A[max]
A[max]
maxpos
maxpos :=:= rr
if
if max
max !=
!= ii
swap(A,i,maxpos)
swap(A,i,maxpos)
Heapify(A,maxpos,n)
Heapify(A,maxpos,n)
Building a Heap
BuildHeap(A)
BuildHeap(A)
for
for ii := ⌊n/2
:= ⌊n /2⌋⌋ to
to 11 do
do
Heapify(A,
Heapify(A, i, i, n)
n)
Building a Heap/2
1 1
2
4 2
4
3 3
1 3 1 3
4 5 6 7 4 5 6 7
2 16 9 10 2 16 9 10
8 9 10 8 9 10
14 8 7 14 8 7
4 1 3 2 16 9 10 14 8 7 4 1 3 2 16 9 10 14 8 7
●
Heapify(A, 7, 10)
●
Heapify(A, 6, 10)
●
Heapify(A, 5, 10)
Building a Heap/3
1 1
2
4 2
4
3 3
1 3 1 3
4 5 6 7 4 5 6 7
2 16 9 10 14 16 9 10
8 9 10 8 9 10
14 8 7 2 8 7
4 1 3 2 16 9 10 14 8 7 4 1 3 14 16 9 10 2 8 7
●
Heapify(A, 4, 10)
Building a Heap/4
1 1
2
4 2
4
3 3
1 3 1 10
4 5 6 7 4 5 6 7
14 16 9 10 14 16 9 3
8 9 10 8 9 10
2 8 7 2 8 7
4 1 3 14 16 9 10 2 8 7 4 1 10 14 16 9 3 2 8 7
●
Heapify(A, 3, 10)
Building a Heap/5
1 1
2
4 2
4
3 3
1 3 16 10
4 5 6 7 4 5 6 7
14 16 9 10 14 7 9 3
8 9 10 8 9 10
2 8 7 2 8 1
4 1 10 14 16 9 3 2 8 7 4 16 10 14 7 9 3 2 8 1
●
Heapify(A, 2, 10)
Building a Heap/6
1 1
2
4 2
16
3 3
16 10 14 10
4 5 6 7 4 5 6 7
14 7 9 3 8 7 9 3
8 9 10 8 9 10
2 8 1 2 4 1
4 16 10 14 7 9 3 2 8 1 16 14 10 8 7 9 3 2 4 1
●
Heapify(A, 1, 10)
(1 ' 1 / x) 2
k *0
log n
h 1/ 2
T (n) *O(n . h ) *O(n 2
) *O(n)
h *0 2 (1 ' 1 / 2)
HeapSort
Heapsort(A)
Heapsort(A)
BuildHeap(A)
BuildHeap(A) O(n)
O(n)
for
for ii :=
:= nn toto 22 do
do nntimes
times
swap(A,1,i)
swap(A,1,i) O(1)
O(1)
nn :=
:= nn -- 11 O(1)
O(1)
Heapify(A,
Heapify(A, 1, 1, n)
n) O(log
O(logn)
n)
Heapsort 16 14 10
14 10 8 10 8 9
8 7 9 3 4 7 9 3 4 7 1 3
2 4 1 2 1 16 2 14 16
9 8 7
8 3 7 3 4 3
4 7 1 2 4 2 1 9 1 2 8 9
10 14 16 10 14 16 10 14 16
4 3 2
2 3 2 1 1 3
1 7 8 9 4 7 8 9 4 7 8 9
10 14 16 10 14 16 10 14 16
1
2 3
4 7 8 9 1 2 3 4 7 8 9 10 14 16
10 14 16
Heapsort: Summary
• Heapsort uses a heap data structure to improve
selection sort and make the running time asymptotically
optimal
• Running time is O(n log n) – like Merge Sort, but unlike
selection, insertion, or bubble sorts
• Sorts in place – like insertion, selection or bubble sorts,
but unlike merge sort
• The heap data structure is also used for other things
than sorting
●
About sorting algorithms
●
Heapsort
– Complete binary trees
– Heap data structure
• Quicksort
– a popular algorithm
– very fast on average
Quicksort
Characteristics
– Sorts in place
(like insertion sort, but unlike merge sort)
i.e., does not require an additional array
– Very practical, average sort performance O(n log n)
(with small constant factors), but worst case O(n2)
Quicksort(A,l,r)
if l < r then
m := Partition(A,l,r)
Quicksort(A,l,m-1)
Quicksort(A,m+1,r)
Partition
INPUT: A[1..n] – an array of integers
l,r – integers satisfying 1 ≤ l ) r ≤ n
OUTPUT: m – an integer with l ≤ m ≤ r
a permutation of A[l..r] such that
A[i]< A[m] for all i with l ≤ i ) m
A[m]≤ A[i] for all i with m ) i ≤ r
int Partition(A,l,r)
p := A[m]; // pivot, used for the split
ll := l-1; // last of the little ones
for bu := l to r-1 do
// bu is the beginning of the unknown area
if A[bu] < p
then swap(A,ll+1,bu); ll++;
// all elements < p are little ones
swap(A,ll+1,m)
// move the pivot into the middle position
Master Informatique Data Structures and Algorithms
38
Chapter
4 Sor4ng:
Heapsort
and
Quicksort
i i j j
17 12 6 19 23 8 5 10
int Partition(A,l,r)
i j
01 p := A[r]
02 i := l-1 + p =10 + 10 12 6 19 23 8 5 17
03 j := r+1
04 while TRUE i j
05 repeat j := j-1
10 5 6 19 23 8 12 17
06 until A[j] + p
07 repeat i := i+1
08 until A[i] - p j i
09 if i<j 10 5 6 8 23 19 12 17
10 then swap(A,i,j)
11 else return i
10 5 6 8 23 19 12 17
Quicksort with
Partitioning from the Endpoints
Quicksort(A,l,r)
if l < r then
m := Partition(A,l,r)
Quicksort(A,l,m)
Quicksort(A,m+1,r)
Analysis of Quicksort
• Assume that all input elements are distinct
• The running time depends on the distribution of splits
Best Case
• If we are lucky, Partition splits the array evenly:
T(n) = 2 T(n/2) + Θ(n)
n n
n/2 n/2 n
n/4 n/4 n/4 n/4 n
log n n/8 n/8 n/8 n/8 n/8 n/8 n/8 n/8 n
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 n
Θ(n log n)
Worst Case
• What is the worst case?
• One side of the partition has one element|
• T(n) = T(n-1) + T(1) + Θ(n)
= T(n-1) + 0 + Θ(n)
n
= . Θ( k )
k *1
n
= Θ%. k )
k *1
= Θ(n2)
Worst Case/2
n n
1 n-1 n
1 n-2 n-1
n 1 n-3 n-2
1
2 3
1 1 2
2
Θ(n )
Worst Case/3
• When does the worst case appear?
=> one of the partition segments is empty
– input is sorted
– input is reversely sorted
• But sorted input yields the best case for insertion sort
Analysis of Quicksort
Suppose the split is 1/10 : 9/10
n n
(1/10)n (9/10)n n
10log n
(1/100)n (9/100)n (9/100)n (81/10)n n
10/9
log n
1 (81/1000)n (729/1000)n n
+n
1 +n
Θ(n log n)
1 n-1
n Θ(n)
Randomized Quicksort
• Assume all elements are distinct
• Partition around a random element
• Consequently, all splits
1:n-1,
2:n-2,
...,
n-1:1
are equally likely with probability 1/n.
Randomized Quicksort/2
int RandomizedPartition(A,l,r)
i := Random(l,r)
exchange A[r] and A[i]
return Partition(A,l,r)
RandomizedQuicksort(A,l,r)
if l < r then
m := RandomizedPartition(A,l,r)
RandomizedQuicksort(A,l,m-1)
RandomizedQuicksort(A,m+1,r)
Summary
• Heapsort
– same idea as Max sort, but heap data structure
helps to find the maximum quickly
– a heap is a nearly complete binary tree,
which here is implemented in an array
– worst case is n log n
• Quicksort
– partition-based: extreme case of D&C,
no work is spent on combining results
– popular, behind Unix ”sort” command
– very fast on average
– worst case performance is quadratic
Master Informatique Data Structures and Algorithms
54
Chapter
4 Sor4ng:
Heapsort
and
Quicksort
Next Chapter
• Dynamic data structures
– Pointers
– Lists, trees
• Abstract data types (ADTs)
– Definition of ADTs
– Common ADTs