Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27
Recursive Quicksort Recursive Quicksort Data Structures in Java with JUnit Data Structures in Java with JUnit © © Rick Mercer Rick Mercer

Transcript of Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Page 1: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Recursive QuicksortRecursive Quicksort

Data Structures in Java with JUnitData Structures in Java with JUnit©©Rick MercerRick Mercer

Page 2: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Quicksort: Quicksort: O(n log n) SortingO(n log n) Sorting

Quicksort was discovered by Tony Hoare 1962Quicksort was discovered by Tony Hoare 1962Here is an outline of his famous algorithm:Here is an outline of his famous algorithm:

Pick one item from the array--call it the pivotPick one item from the array--call it the pivot Partition the items in the array around the pivot so all Partition the items in the array around the pivot so all

elements to the left are elements to the left are to the pivot and all elements to the pivot and all elements to the right are greater than the pivotto the right are greater than the pivot

Use recursion to sort the two partitions Use recursion to sort the two partitions a snapshota snapshotpivot

partition: items > pivotpartition 1: items pivot

Page 3: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Before and AfterBefore and After

Let's sort integersLet's sort integers Pick the leftmost one (27) as the pivot valuePick the leftmost one (27) as the pivot value The array before call to partition(a, 0, n-1)The array before call to partition(a, 0, n-1)

Array looks like this after Array looks like this after first first partition is donepartition is done

27 14 9 22 8 41 56 31 14 53 99 11 2 24

24 14 9 22 8 14 11 2 27 53 99 56 31 41

pivotitems < pivot items > pivot

Page 4: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

The partition methodThe partition method

ppartitionartition divvies up divvies up aa around the split and around the split and returnsreturns the position of the split, an integer in the the position of the split, an integer in the range of 0..n-1 range of 0..n-1 The postcondition of partition:The postcondition of partition:

a[first]..a[split-1] <= a[split] a[first]..a[split-1] <= a[split] && &&

a[split+1]..a[last] > a[split]a[split+1]..a[last] > a[split]

Notes:Notes: May be more than 1 element equal to the pivotMay be more than 1 element equal to the pivot Put them in left partition Put them in left partition could have been the rightcould have been the right

Page 5: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Recursive call to sort smaller Recursive call to sort smaller part of the arraypart of the array

quickSort(a, split+1, last);quickSort(a, split+1, last); // sort right// sort right

QuickSort the right. At some pointQuickSort the right. At some point Pivot will be 53Pivot will be 53 Assume left portion is already sortedAssume left portion is already sorted

24 14 9 22 8 14 11 2 27 53 99 56 31 41

2 8 9 11 14 14 22 24 27 31 41 53 99 56

pivot

items < pivot items > pivot

left is already sorted, begin to sort part to the right of split

Page 6: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Complete the sortComplete the sort

// sort left and right around new split// sort left and right around new split quickSort(a, first, split-1);quickSort(a, first, split-1);

// sort right// sort right quickSort(a, split+1, last); quickSort(a, split+1, last);

2 8 9 11 14 14 22 24 27 31 41 53 99 56

2 8 9 11 14 14 22 24 27 31 41 53 99 56

2 8 9 11 14 14 22 24 27 31 41 53 99 56

2 8 9 11 14 14 22 24 27 31 41 53 56 99

Entire array is now sorted

Page 7: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Start Over (i ==1)Start Over (i ==1)

Now let's back up and start with empty partitionsNow let's back up and start with empty partitions

int partition(int a[], int first, int last) {int partition(int a[], int first, int last) { int lastSmall = first;int lastSmall = first; int i = (first + 1);int i = (first + 1); // Beginning of unknowns// Beginning of unknowns

Compare all items from a[i]..a[last]Compare all items from a[i]..a[last] if a[i] > a[first] (the pivot), do nothingif a[i] > a[first] (the pivot), do nothing if a[i] <= a[first], swap a[lastSmall+1] with a[i]if a[i] <= a[first], swap a[lastSmall+1] with a[i]

27 41 14 56 31 9 22 8 14 53 99 11 2 24

first lastSmall i unknown items (all are unknown--except first)

Page 8: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Result of the 1st loop Result of the 1st loop iteration(i==2)iteration(i==2)

27 41 14 56 31 9 22 8 14 53 99 11 2 24

first lastSmall i unknown items

partition 1: all items <= pivot partition 2: all items > pivot

The following array shows no changes were made in the array since a[i] <= a[first] was false

So simply add 1 to i (i++)--create 2 partitions Now partition 1 has one element (the pivot 27)

and partition 2 has 1 element (41)

Page 9: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Result of the 2nd loop Result of the 2nd loop iteration(i==3)iteration(i==3)

27 14 41 56 31 9 22 8 14 53 99 11 2 24

first lastSmall i unknown items

partition 1: all items <= pivot partition 2: all items > pivot

The following array shows a swap was made in the array since a[i] <= a[first] was true (14 < 27)

a[i] (14) is swapped with a[lastSmall+1] (41) lastSmall gets incremented to point to the last

element in partition 1 i gets incremented to reference 56

Page 10: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Result of the 3rd loop Result of the 3rd loop iteration(i==4)iteration(i==4)

27 14 41 56 31 9 22 8 14 53 99 11 2 24

first lastSmall i unknown items

partition 1: all items <= pivot partition 2: all items > pivot

The following array shows no swap was made in the array since a[i] <= a[first] was false

lastSmall does NOT get incremented i gets incremented to reference 31

Page 11: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Result of the 4th loop Result of the 4th loop iteration(i==5)iteration(i==5)

27 14 41 56 31 9 22 8 14 53 99 11 2 24

first lastSmall i unknown items

partition 1: all items <= pivot partition 2: all items > pivot

The following array shows no swap was made in the array since a[i] <= a[first] was false

lastSmall does NOT get incremented i gets incremented to reference 9

Page 12: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Result of the 5th loop Result of the 5th loop iteration(i==6)iteration(i==6)

27 14 9 56 31 41 22 8 14 53 99 11 2 24

first lastSmall i unknown items

partition 1: all items <= pivot partition 2: all items > pivot

The following array shows a swap was made in The following array shows a swap was made in the array since a[i] <= a[first] was true (9 < 27)the array since a[i] <= a[first] was true (9 < 27)

a[i] (9) is swapped with a[lastSmall+1] (41)a[i] (9) is swapped with a[lastSmall+1] (41) lastSmall gets incremented to point to the last lastSmall gets incremented to point to the last

element in partition 1element in partition 1 i++ points to the first unknown (22)i++ points to the first unknown (22)

Page 13: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 56 31 41 8 14 53 99 11 2 24

first lastSmall i unknown items

partition 1: all items <= pivot partition 2: all items > pivot

i == 7i == 7

Page 14: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 8 56 31 41 14 53 99 11 2 24

first lastSmall i unknown

partition 1: all items <= pivot partition 2: all items > pivot

i == 8i == 8

Page 15: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 8 14 56 31 41 53 99 11 2 24

first lastSmall i unknown

partition 1: all items <= pivot partition 2: all items > pivot

i == 9 i == 9

Page 16: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 8 14 56 31 41 53 99 11 2 24

first lastSmall i unknown

partition 1: all items <= pivot partition 2: all items > pivot

i == 10 i == 10

Page 17: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 8 14 56 31 41 53 99 11 2 24

first lastSmall i unknown

partition 1: all items <= pivot partition 2: all items > pivot

i == 11 i == 11

Page 18: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 8 14 11 56 31 41 53 99 2 24

first lastSmall i unknown

partition 1: all items <= pivot partition 2: all items > pivot

i == 12 i == 12

Page 19: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

27 14 9 22 8 14 11 2 56 31 41 53 99 24

first lastSmall i unknown

partition 1: all items <= pivot partition 2: all items > pivot

i == 13 i == 13

Page 20: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Result of the 14th loop Result of the 14th loop iteration(i==14)iteration(i==14)

27 14 9 22 8 14 11 2 24 53 99 56 31 41

first lastSmall i

partition 1: all items <= pivot partition 2: all items > pivot

The following array shows what happens after traversing the entire array with this loop (i>last):for (i = first + 1; i <= last; i++) {for (i = first + 1; i <= last; i++) { if(a[i] <= a[first] ) {if(a[i] <= a[first] ) { lastSmall++;lastSmall++; swapElements(a, lastSmall, i);swapElements(a, lastSmall, i); } }

}}

Page 21: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Post Loop DetailPost Loop Detail

Now place the pivot into where we expect the Now place the pivot into where we expect the pivot to be: in-between the two partitionspivot to be: in-between the two partitions

swapElements( a, first, lastSmall );swapElements( a, first, lastSmall );

Then we can return lastSmall for the next callThen we can return lastSmall for the next call return lastSmall;return lastSmall;

24 14 9 22 8 14 11 2 27 53 99 56 31 41

first lastSmall (pivot position)

partition 1: all items <= pivot partition 2: all items > pivot

Page 22: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

quickSort is called like this:quickSort is called like this:quickSort(a, 0, n-1)quickSort(a, 0, n-1)

void quickSort(int a[], int first, int last) {void quickSort(int a[], int first, int last) { // precondition: a is an array to be sorted from// precondition: a is an array to be sorted from // a[first]..a[last]// a[first]..a[last] if(first >= last) if(first >= last) return; return; // Done: we have an empty array// Done: we have an empty array

// The difficult algorithm is in partition// The difficult algorithm is in partition int split = partition ( a, first, last );int split = partition ( a, first, last );

// Recursively Quicksort left, then right// Recursively Quicksort left, then right quickSort(a, first, split-1); quickSort(a, first, split-1); // sort left// sort left quickSort(a, split+1, last); quickSort(a, split+1, last); // sort right // sort right

// post: the array a is sorted// post: the array a is sorted }}

Page 23: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Analyzing QuicksortAnalyzing Quicksort

The critical statement happens in the comparison The critical statement happens in the comparison of the for loop of the partition functionof the for loop of the partition function

if(a[i] <= a[first]) if(a[i] <= a[first]) So how many times is partition called?So how many times is partition called? And what are the values for first and last (# And what are the values for first and last (#

comparisons)?comparisons)?

If the pivot element is near the mode, we don't If the pivot element is near the mode, we don't have many calls to QuickSort, it is O(log n)have many calls to QuickSort, it is O(log n)

Page 24: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

The best of Quicksort, The best of Quicksort, the worst of Quicksortthe worst of Quicksort

In the best case (1st element is always middle In the best case (1st element is always middle value) with 7 elements, call partition 3 timesvalue) with 7 elements, call partition 3 times

first == 0, last == 6first == 0, last == 6 // 6 comparisons// 6 comparisons first == 0, last == 2first == 0, last == 2 // 2 comparisons// 2 comparisons first == 4, last == 6first == 4, last == 6 // 2 comparisons// 2 comparisons

In the worst case, (sorted array), with 7 In the worst case, (sorted array), with 7 elements, partition is called elements, partition is called

first == 0, last == 6first == 0, last == 6 // 6 comparisons// 6 comparisons first == 1, last == 6first == 1, last == 6 // 5 comparisons// 5 comparisons first == 2, last == 6first == 2, last == 6 // 4 comparisons// 4 comparisons first == 3, last == 6first == 3, last == 6 // 3 comparisons// 3 comparisons first == 4, last == 6first == 4, last == 6 // 2 comparisons// 2 comparisons first == 5, last == 6first == 5, last == 6 // 1 comparison// 1 comparison

Page 25: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Best Case:Best Case:

[ 4, 1, 3, 2, 6, 5, 7 ][ 4, 1, 3, 2, 6, 5, 7 ]

[ 2, 1, 3, [ 2, 1, 3, 44, 6, 5, 7 ], 6, 5, 7 ]

[ 2, 1, 3] [ 6, 5, 7 ][ 2, 1, 3] [ 6, 5, 7 ]

[ 1, [ 1, 22, 3] [ 5, , 3] [ 5, 66, 7 ], 7 ]

[1] [3] [5] [7][1] [3] [5] [7]

Page 26: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

Worst CaseWorst Case

[ 1, 2, 3, 4, 5, 6, 7][ 1, 2, 3, 4, 5, 6, 7]

[] [2, 3, 4, 5, 6, 7][] [2, 3, 4, 5, 6, 7]

[] [3, 4, 5, 6, 7][] [3, 4, 5, 6, 7]

[] [4, 5, 6, 7][] [4, 5, 6, 7]

[] [5, 6, 7][] [5, 6, 7]

[] [6, 7][] [6, 7]

[] [7][] [7]

[] [][] []

Page 27: Recursive Quicksort Data Structures in Java with JUnit ©Rick Mercer.

The Best and Worst The Best and Worst continuedcontinued

So in the worst case, partition is called n-1 So in the worst case, partition is called n-1 times:times:

(n-1)+(n-2)+ ... + 1 comparisons = O(n(n-1)+(n-2)+ ... + 1 comparisons = O(n22))

The worst case of Quicksort may be the same The worst case of Quicksort may be the same as Selection Sort, which is O(nas Selection Sort, which is O(n22))

Quicksort is used because of its best and Quicksort is used because of its best and average casesaverage cases