Yan Shi CS/SE 2630 Lecture Notes 13. Sorting Yan Shi CS/SE 2630 Lecture Notes Partially adopted from C++ Plus Data Structure textbook slides
Basic Sorting Algorithms Selection sort: select the current smallest to put in the current first position Bubble sort: bubble small values up Insertion sort: insert new items into sorted list They are all O(n2)! Use recursion to get more efficient sorting: O(nlog2n) Heap sort Merge sort Quick sort
Merge Sort Basic idea: divide and conquer divide the list into two parts sort each half (recursively) merge (combine) the two parts 74 36 . . . 95 75 29 . . . 52 [last] [first] [middle] [middle + 1] 36 74 . . . 95 29 52 . . . 75
Merge Sort Implementation // Recursive merge sort algorithm template <class ItemType > void MergeSort( ItemType values[ ] , int first , int last ) // Pre: first <= last // Post: Array values[first..last] sorted into // ascending order. { if ( first < last ) // general case int middle = ( first + last ) / 2; MergeSort ( values, first, middle ); MergeSort( values, middle + 1, last ); // now merge two subarrays // values [ first . . . middle ] with // values [ middle + 1, . . . last ]. Merge(values, first, middle, middle + 1, last); } // How to merge?
Merge 1 3 18 20 2 5 10 16 30 1 1 < 2 fill 1 and move leftFirst 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightFirst rightLast 1 1 < 2 fill 1 and move leftFirst
Merge 1 3 18 20 2 5 10 16 30 1 2 3 > 2 fill 2 and move rightFirst 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightFirst rightLast 1 2 3 > 2 fill 2 and move rightFirst
Merge 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightFirst rightLast 1 2 3 3 < 5 fill 3 and move leftFirst
Merge 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightFirst rightLast 1 2 3 5 18 > 5 fill 5 and move rightFirst
Merge 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightFirst rightLast 1 2 3 5 10 18 > 10 fill 10 and move rightFirst
Merge 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightFirst rightLast 1 2 3 5 10 16 18 > 16 fill 16 and move rightFirst
Merge 1 3 18 20 2 5 10 16 30 leftFirst leftLast rightLast rightFirst 1 2 3 5 10 16 18 18 < 30 fill 18 and move leftFirst
Merge 1 3 18 20 2 5 10 16 30 leftLast rightLast leftFirst rightFirst 1 2 3 5 10 16 18 20 20 < 30 fill 20 and move leftFirst leftFirst > leftLast, stop
Merge 1 3 18 20 2 5 10 16 30 leftLast rightLast leftFirst rightFirst 1 2 3 5 10 16 18 20 30 Append the remaining of the right part DONE!
Merge Algorithm Given left array and right array, create a temp array of the size as the sum of left and right while more items in left AND more items in right if values[leftFirst] < values[rightFirst] temp[i] = values[leftFirst]; leftFirst++ else temp[i] = values[rightFirst]; rightFirst++ i++ Copy any remaining item from the left half to temp Copy any remaining item from the right half to temp Copy the sorted temp array back to values array Issue: need a second array to merge, more space consuming compared to quicksort and heapsort
Merge Sort Complexity O(nlog2n)! 16 8 8 4 4 4 4 2 2 2 2 2 2 2 2 8 8 4 4 4 4 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Quick Sort Divide and conquer! Can we divide a list into two pieces and sort both independently? Basic idea of algorithm: select a value from the list (pivot) partition the list so that all smaller values are to the left and all larger values are to the right of the pivot sort left portion (recursively) sort right portion Key is splitting: organize the list as values smaller (or equal to) pivot (split point) pivot values larger than pivot Question: Where to split?
Quick Sort Implementation // Recursive quick sort algorithm template <class ItemType > void QuickSort ( ItemType values[ ] , int first , int last ) // Pre: first <= last // Post: Sorts array values[ first, last ] into ascending order { if ( first < last ) // general case int splitPoint ; Split ( values, first, last, splitPoint ) ; // values [first]..values[splitPoint - 1] <= splitVal // values [splitPoint] == splitVal // values [splitPoint + 1]..values[last] > splitVal QuickSort(values, first, splitPoint - 1); QuickSort(values, splitPoint + 1, last); } } ; // How to decide splitPoint?
Before Split We choose the first item as the pivot: splitVal = 9 GOAL: place splitVal in its proper position with all values less than or equal to splitVal on its left and all larger values on its right 9 20 6 18 14 3 60 11 values[first] [last]
After Split splitVal = 9 How do we do that? 6 3 9 18 14 20 60 11 smaller values larger values in left part in right part 6 3 9 18 14 20 60 11 values[first] [last] splitVal in correct position How do we do that?
Split: Iteration 1 splitVal = 9 9 20 6 18 14 3 60 11 left right 20 > 9, not on correct side stop left 11 > 9, on correct side right -- 60 > 9, on correct side right – 3 < 9, not on correct side stop right 9 20 6 18 14 3 60 11 left right left <= right, swap [left] and [right], move them toward each other 9 3 6 18 14 20 60 11 left right
Split: Iteration 2 splitVal = 9 9 3 6 18 14 20 60 11 left right 6 < 9, on correct side left++ 18 > 9, not on correct side stop left 14 > 9, on correct side right-- 18 > 9, on correct side right-- left > right, stop right 9 3 6 18 14 20 60 11 right left left > right, we stop the loop and make right the split point swap 9 and 6 6 3 9 18 14 20 60 11 split point
Split Algorithm void Split(ItemType a[], int first, int last, int & splitpt) { ItemType splitVal = a[first]; // use first element as the pivot int left = first + 1, right = last; do while (left <= right && a[left] <= splitVal) ++left; while (left <= right && a[right] > splitVal) --right; if ( left < right) swap( a[left++], a[right--]); } while (left <= right); splitpt = right; swap(a[first], a[splitpt]);
Let’s finish the quick sort 6 3 9 18 14 20 60 11 split point 3 6 11 14 18 60 20 3 11 14 20 60 14 20 3 6 9 11 14 18 20 60
Quick Sort of N elements: How many comparisons? N For first call, when each of N elements is compared to the split value 2 * N/2 For the next pair of calls, when N/2 elements in each “half” of the original array are compared to their own split values. 4 * N/4 For the four calls when N/4 elements in each “quarter” of original array are compared to their own split values. . . HOW MANY SPLITS CAN OCCUR?
Quick Sort of N elements: How many splits can occur? It depends on the order of the original array elements! If each split divides the subarray approximately in half, there will be only log2N splits, and QuickSort is O(N*log2N). But, if the original array was sorted will split up the array into parts of unequal length, with one part empty, and the other part containing all the rest of the array except for split value itself. In this case, there can be as many as N-1 splits, and QuickSort is O(N2). solution: use the middle value as the split value and swap with the first value to begin with.
Sorting Objects When sorting an array of objects we are manipulating references to the object, and not the objects themselves