CSC297.Java, Class 28: Sorting, Particularly Preconditions and Postconditions Admin: * New homework: * Write prepost for sortInPlace * Try to come up with a quick way of sorting a group of numbers between 1 and 100 when you may have duplicates. Hint: Think about the post office. * Implement the partitioning algorithm * Weekly Bishop-check Topics: * PP: swap * PP: findSmallest * PP: sortInPlace * PP: insert (?) * Faster sorts * Overview of mergesort * Overview of quicksort Reminder: * Preconditions and postconditions are intended for an adversarial world * If the postconditions are too weak, the programmer will not do what the client intends. * If the preconditions are too weak, the client will send bad data and sue when the procedure fails to work "as advertised". /** * Procedure: * swap * Parameters: * stuff, an array of objects * x, an integer * y, an integer * Purpose: * Swap the elements at indexes x and y in stuff. * Produces: * Nothing; called for side effects. * Preconditions: * stuff must be nonempty. * x and y must be "valid" indices. That is, 0 <= x,y < stuff.length * Exists X s.t. stuff[x] == X * Exists Y s.t. stuff[y] == Y * Postconditions: * The value that was at position x is now at position y. * stuff[x] == Y * The value that was at position y is now at position x. * stuff[y] == X * No other values have changed. */ /** * Procedure: * findSmallest * Parameters: * stuff, an array of objects * startIndex, an integer * compare, a comparator * Purpose: * Find the index of the "smallest" value in stuff that appears * at position startIndex or after. * Produces: * indexOfSmallest, an integer * Preconditions: * stuff must be nonempty. * 0 <= startIndex < stuff.length * compare.mayPrecede must be applicable to all pairs of elements * from stuff. * compare.mayPrecede must be transitive and reflexive. * Postconditions: * compare.mayPrecede(stuff[indexOfSmallest], stuff[i]) for all * i, startIndex <= i < stuff.length. */ /** * Procedure: * sortOutOfPlace * Parameters: * stuff, an array * compare, a comparator * Purpose: * Build a new array that contains the elements of stuff in * ascending order. * Produces: * sorted, an array. * Preconditions: * compare.mayPrecede can be applied to any pair of objects in sutff. * stuff is nonempty. * compare.mayPrecede must be transitive. * Postconditions: * stuff is unchanged. * sorted is sorted, that is for all 0 <= x < y < sorted.length * compare.mayPrecede(sorted[x], sorted[y]) * alternately, for all 0 <= i < sorted.length-1 * compare.mayPrecede(sorted[i], sorted[i+1]) * sorted is a permutation of stuff. */ ---- Q: Can we write sorting algorithms faster than O(N^2)? A: Yes, yes we can Q: How? A: Use the wonder of "divide and conquer". How can we divide an array in half? * Use indices to keep track of the part of the array of interest. To sort a subarray ... If there are 0 or 1 elements in the subarray, sorted If there are some small number, use insertionSort O/w sort the first half sort the second half merge the two together (usually into a new array) For in-place: Copy back to the main array Running time: Note that merge sort is recursive, so we'll need to use recurrence relations f(0) = 1 f(1) = 1 f(n) = f(n/2) + f(n/2) + 2*n f(n) = 2*f(n/2) + 2*n f(n) = 2*(2*f(n/2/2) + 2*n/2) + 2*n f(n) = 4*f(n/4) + 2*n + 2*n f(n) = 4*f(n/4) + 4*n f(n) = 4*(2*f(n/8) + 2*n/4) + 4*n f(n) = 8*f(n/8) + 6*n f(n) = 2^k*f(n/2^k) + 2*k*n When k = log_2(n) f(n) = n*f(1) + 2*log_2(n)*n f(n) is in O(n*log_2(n)) Significantly faster than the O(n^2) algorithms, but can't be done in place. Can we go faster than O(n*log_2(n))? * Not for algorithms based on compare-and-swap What's a quick way of sorting the a permutation of 1,2,...,100? * Spit out the sequence of numbers Other O(n*log_2(n)) algorithms: * Quicksort * Heapsort (later this semester) Quicksort: * "Randomized" divide and conquer * Rearrange the subarray before you recurse * In particular, segment the subarray so that "small" elements are at the left and "large" elements are at the right. * Sort each half * You're done! Question: * How do you get small elements on the left and large elements on the right? * Pick a "pivot", a number that you expect to be larger than about half the elements and smaller than about half the elements * Start at both ends of the array. At the right, move left until you see a small element. At the left, move right until you see a large element. Swap the two. Repeat.