2
Note about Merge Sort Typically done with a second array Why? – Since elements in both halves are already sorted, easier to compare elements at the beginning of the list/array – More memory allows faster movement of data

3
Note about Merge Sort If odd number of elements, you have two different options for splitting – Option 1: split so that the left half has one more than the right half (you are tested on this way) – Option 2: split so that the right half has one more than the left half – Either option works as long as you are consistent in your splitting (i.e. always give more to the left or always give more to the right)

4
Note about Merge Sort The way that you split matters! You must merge with the numbers you split from – Has to do with the way recursion works – Recursion breaks the sorting problem into a smaller sorting problem Have to look at each half as a new sorting problem Cannot sort with numbers from another problem unless you are merging with numbers you previously split from

6
Bubble Sort Starting from the beginning of the list, compare every adjacent pair, swap their position if they are not in the right order. After each iteration, one less element (the last one) is needed to be compared until there are no more elements left to be compared.

7
Quick Sort Pick an element, called a pivot, from the list. Reorder the list so that – all elements with values less than the pivot come before the pivot – all elements with values greater than the pivot come after it – equal values can go either way – After this partitioning, the pivot is in its final position. This is called the partition operation. Recursively sort the sub-list of lesser elements and the sub-list of greater elements.

8
Efficiency What is it? Why do we care? How do we measure?

9
What does “efficiency” mean? Measure of how long the algorithm takes to run to completion relative to the number of inputs it is given – For our sorting algorithms, inputs are arrays, ArrayLists, other lists, etc.

11
How do we measure efficiency? Time? (Wall-clock time or execution time) – Advantages: easy to measure, meaning is obvious – Appropriate if you care about actual time (e.g. real-time systems) – Disadvantages: applies only to specific data set, compiler, machine, etc. Typically not a good idea to measure by actual time – Computers perform at different speeds

12
How do we measure efficiency? Better idea? Number of times certain statements are executed: – Advantages: more general (not sensitive to speed of machine). – Disadvantages: doesn’t tell you actual time, still applies only to specific data sets.

13
How do we measure efficiency? Symbolic execution times: – That is, formulas for execution times or statement counts in terms of input size. – Advantages: applies to all inputs, makes scaling clear. – Disadvantage: practical formula must be approximate, may tell very little about actual time.

14
How do we measure efficiency? Since we are approximating anyway, pointless to be precise about certain things: – Behavior on small inputs: Can always pre-calculate some results. Times for small inputs not usually important. – Constant factors (as in “off by factor of 2”): Just changing machines causes constant-factor change. How to abstract away from (i.e., ignore) these things? – Order notation

17
Random or Deterministic Random  different every time Deterministic  consistent every time Which is more efficient? – E.g. int[] arr = {11, 12, 13, 14, 15, 16, 17, 18}; Randomly find index of 18? Deterministically find index of 18? – Would it work if 18 was not in the array?

18
Iterative or Recursive Iterative more efficient in many cases Recursive can be more efficient in some cases (e.g. merge sort) Consider two different algorithms for calculating the 40 th Fibonacci number – Recursive takes a really long time – Iterative only does each calculation once