class: middle, center # Lecture 9 ### 21 October 2024 .smaller[ Admin Matters
Unit 21: Searching
Unit 22: Sorting
] --- ![meme](figures/meme/week0-10.jpg) --- ### Adjustment to Schedule - PE1 tomorrow (check your venue) - Exercise 6 (to be released on Tuesday night) - Quiz 9 (deadline extended to Thursday night) --- ### Catch-Up Session III - Saturday, 28 October - 10 AM - 12 PM --- class: middle, center ## Searching --- Given an array of items $L$ and a query $q$, return the position of $q$ in $L$ (or -1 if $q$ is not in $L$). --- .smaller[ ```C long search(long n, const long list[], long q) { for (long i = 0; i < n; i += 1) { if (list[i] == q) { return i; } } return -1; } ``` ] --- .smaller[ ```C // Look for q in list[i]..list[j]. long search(const long list[], long i, long j, long q) { if (i > j) { return -1; } : : : : : : : : : } ``` ] --- .smaller[ ```C // Look for q in list[i]..list[j]. long search(const long list[], long i, long j, long q) { if (i > j) { return -1; } long mid = (i+j)/2; if (list[mid] == q) { return mid; } : : : : : } ``` ] --- .smaller[ ```C // Look for q in list[i]..list[j]. long search(const long list[], long i, long j, long q) { if (i > j) { return -1; } long mid = (i+j)/2; if (list[mid] == q) { return mid; } long found = search(list, i, mid-1, q); if (found >= 0) { return found; } return search(list, mid+1, j, q); } ``` ] --- class: left $T(1) = 1$ $T(n) = 2T\left(\frac{n}{2}\right) + 1, n > 1$ --- Impossible to look for $q$ faster than $O(n)$, since we need to check every element to know that it is there or not. --- Given a _sorted_ array of items $L$ and a query $q$, return the position of $q$ in $L$ (or -1 if $q$ is not in $L$). --- .smaller[ ```C // Look for q in list[i]..list[j]. long search(const long list[], long i, long j, long q) { if (i > j) { return -1; } long mid = (i+j)/2; if (list[mid] == q) { return mid; } : : : : } ``` ] --- .smaller[ ```C // Look for q in list[i]..list[j]. long search(const long list[], long i, long j, long q) { if (i > j) { return -1; } long mid = (i+j)/2; if (list[mid] == q) { return mid; } if (list[mid] > q) { return search(list, i, mid-1, q); } return search(list, mid+1, j, q); } ``` ] --- .tiny[ ```C // Look for q in list[i]..list[j]. long search(const long list[], long i, long j, long q) { if (i > j) { return -1; } long mid = (i+j)/2; if (list[mid] == q) { return mid; } if (list[mid] > q) { return search(list, i, mid-1, q); } return search(list, mid+1, j, q); } ``` ] --- $T(1) = 1$ $T(n) = T\left(\frac{n}{2}\right) + 1, n > 1$ --- class: middle,center ## Sorting --- ### Counting Sort -- .center[If we knew how many of each number there were, we can just output each number the correct amount of times.] --- class: top ![:scale 80%](figures/lec09-sorting/counting-3-1.png) --- class: top ![:scale 80%](figures/lec09-sorting/counting-3-2.png) --- class: top ![:scale 80%](figures/lec09-sorting/counting-3-3.png) --- class: top ![:scale 80%](figures/lec09-sorting/counting-3-4.png) --- class: top ![:scale 80%](figures/lec09-sorting/counting-3-5.png) --- .tiny[ ```C void counting_sort(size_t n, const long in[], long out[]) { size_t freq[MAX + 1] = { 0 }; // sets the entire array to 0 on all elements : : : : : : : : : : : : : : } ``` ] --- .tiny[ ```C void counting_sort(size_t n, const long in[], long out[]) { size_t freq[MAX + 1] = { 0 }; for (size_t i = 0; i < n; i += 1) { freq[in[i]] += 1; // get the frequency of each value } : : : : : : : : : : : } ``` ] --- .tiny[ ```C void counting_sort(size_t n, const long in[], long out[]) { size_t freq[MAX + 1] = { 0 }; for (size_t i = 0; i < n; i += 1) { freq[in[i]] += 1; } size_t outpos = 0; // output position in the output array for (long i = 0; i <= MAX; i += 1) { : // for all possible output values 0 to MAX : // call the possible output value i : : : : : : } } ``` ] --- .tiny[ ```C void counting_sort(size_t n, const long in[], long out[]) { size_t freq[MAX + 1] = { 0 }; for (size_t i = 0; i < n; i += 1) { freq[in[i]] += 1; } size_t outpos = 0; for (long i = 0; i <= MAX; i += 1) { // i here is the value to output // for positions from current output position // to freq[i] after that for (size_t j = outpos; j < outpos + freq[i]; j += 1) { out[j] = i; // set out[j] to be i } // update the output position outpos += freq[i]; } } ``` ] --- ### Counting Sort Analysis ![:scale 80%](figures/lec09-sorting/counting-analysis-1.png) --- ### Counting Sort Analysis ![:scale 80%](figures/lec09-sorting/counting-analysis-2.png) --- ### Counting Sort Analysis We now know it's $O(n + MAX)$. What's the downside of this? -- One slight downside is that it's easy to set $MAX$ to a large value. Imagine an array that looks like: .center[{1, 2, 420420420}] --- ### Selection Sort -- .center[New idea: How about about repeatedly finding the maximum element and putting it in the correct position?] --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-1.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-2.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-3.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-4.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-5.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-6.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-7.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-8.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-9.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-10.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-11.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-12.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-13.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-14.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-15.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-16.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-17.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-18.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-19.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-20.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-21.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-22.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-23.png) --- .smaller[ ```C void selection_sort(size_t n, long list[]) { for (size_t right_end = n; right_end >= 1; right_end -= 1) { size_t max_pos = max(right_end, list); swap(list, max_pos, right_end - 1); } } ``` ] --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-analysis-1.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-analysis-2.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-analysis-3.png) --- ### Selection Sort ![:scale 80%](figures/lec09-sorting/selection-sort-analysis-4.png) --- ### Counting Sort vs. Selection Sort - Counting sort is faster but only works when the range of the inputs is limited - Selection sort is slower and is more general --- .smaller[ ```C void selection_sort(size_t n, long list[]) { for (size_t right_end = n; right_end >= 1; right_end -= 1) { size_t max_pos = max(right_end, list); swap(list, max_pos, right_end - 1); } } ``` ] --- ### Bubble Sort -- .center[New idea: What about we just keep trying to find adjacent numbers that are out of order and make them in order?] --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-1.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-2.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-4.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-5.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-6.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-7.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-8.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-9.png) --- ### Bubble Sort ![:scale 80%](figures/lec09-sorting/bubble-sort-10.png) --- .smaller[ ```C void bubble_pass(size_t last, long a[]) { for (size_t i = 0; i < last; i += 1) { if (a[i] > a[i+1]) { swap(a, i, i+1); } } } ``` ] --- .smaller[ ```C void bubble_pass(size_t last, long a[]) { for (size_t i = 0; i < last; i += 1) { if (a[i] > a[i+1]) { swap(a, i, i+1); } } } void bubble_sort(size_t n, long a[]) { for (size_t last = n - 1; last > 0; last -= 1) { bubble_pass(last, a); } } ``` ] --- ### Insertion Sort -- .center[ Yet Another Idea: If the earlier portion is sorted, then we just have to find where the next element goes. ] --- ### Insertion Sort ![:scale 80%](figures/lec09-sorting/insertion-sort-1.png) --- ### Insertion Sort ![:scale 80%](figures/lec09-sorting/insertion-sort-2.png)--- ### Insertion Sort ![:scale 80%](figures/lec09-sorting/insertion-sort-3.png)--- ### Insertion Sort ![:scale 80%](figures/lec09-sorting/insertion-sort-4.png)--- ### Insertion Sort ![:scale 80%](figures/lec09-sorting/insertion-sort-5.png) --- .smaller[ ```C void insert(long a[], size_t curr) { size_t i = curr; long temp = a[curr]; while (i >= 1 && temp < a[i - 1]) { a[i] = a[i - 1]; i -= 1; } a[i] = temp; } ``` ] --- .smaller[ ```C void insert(long a[], size_t curr) { size_t i = curr; long temp = a[curr]; while (i >= 1 && temp < a[i - 1]) { a[i] = a[i - 1]; i -= 1; } a[i] = temp; } void insertion_sort(size_t n, long a[]) { for (size_t curr = 1; curr < n; curr += 1) { insert(a, curr); } } ``` ] --- 1. the `insert` function takes $O(n)$ time. 2. overall, it also takes $O(n^2)$ time. --- ### Homework - Quiz 9 (extended to Thursday night) - Exercise 6 (released on Tuesday night) - Problem Set 21 - 22 --- class: bottom .tiny[ ]