diff --git a/content/notes/04-requirements.md b/content/notes/04-requirements.md index 96800e09d..6435dbbce 100644 --- a/content/notes/04-requirements.md +++ b/content/notes/04-requirements.md @@ -1,8 +1,14 @@ --- title: "04-requirements" +sr-due: 2022-04-06 +sr-interval: 15 +sr-ease: 232 tags: - info201 - lecture +sr-due: 2022-04-10 +sr-interval: 3 +sr-ease: 250 --- [requirements](notes/requirements.md) diff --git a/content/notes/07-mergesort-1.md b/content/notes/07-mergesort-1.md index cfc6c0811..bbb896961 100644 --- a/content/notes/07-mergesort-1.md +++ b/content/notes/07-mergesort-1.md @@ -1,17 +1,24 @@ --- title: "07-mergesort-1" +sr-due: 2022-04-26 +sr-interval: 23 +sr-ease: 250 tags: - cosc201 - lecture --- -# Divide and conquer +[mergeosrt](notes/mergeosrt.md) + +#unfinished + +# 1 Divide and conquer 1. pre ⇒ break apartinto two or more smaller problems whose size add up to at most n 2. Rec ⇒ solve those problems recursively 3. post ⇒ combine solutions into a solution of the original problem -## 1 quicksort +## 1.1 quicksort pre ⇒ select pivot and split the array @@ -26,79 +33,4 @@ works best of primitive types as they can be stored in the fastest memory locati - memory access can be localised and the comparisions are direct - those advantages are limited when sorting objects of reference type - i that case each element of the array is just a reference to where the object really is -- so there are no local access advantages - -# Mergesort - -a variant of a divide and conquer sorting array - -pre ⇒ split array into two pieces of nearly equal size, - -rec ⇒ sort the pieces, - -post ⇒ merge the pieces - -## 2 Merge - -take the two lowest values - -place the lowest of the two in the next place in the sorted array - -## 3 Implementation - -- given: a and b are sorted arrays. m in an array whose sixe is the sum fo their sizes -- desired outcome: the elements of a and b have been copoed into m in sorted order - -- maiain indices, ai, bi, and mi of the active location in a b and m -- if both ai and bi represent actual indices of a and b, find the one which points to the lesser value (break ties in favour of a) copy that vale into m at mi and increment mi and whichever of ai or bi was used for the copy. -- once one of ai and bi is out of range, copy the rest of the other array into the remainder of m - -```java -public static int[] merge (int[] a int[] b){ - int[] m = new int[a.length + b.length] - int ai = 0, bi = 0, mi = 0; - - while(ai < a.length && bi < b.length) { - if(a[ai] <= b[bi]) m[mi++] = a[ai++]; - else m[mi++] = b[bi++] - } - - while (ai < a.length) m[mi++] = a[ai++]; - while (bi < b.length) m[mi++] = a[bi++]; - - return m; -} -``` - -```java - public static void mergeSort(int[] a){ - mergeSort(a, 0, a.length); - } - - public static void mergeSort(int[] a, int lo, int hi){ - if(hi - lo <= 1) return; - int mid = (hi + lo)/2; - mergeSort(a, lo, mid); - mergeSort(a, mid, hi); - merge(a, lo, mid, hi); - } - - public static void merge(int[] a, int lo, int mid, int hi){ - int[] t = new int [hi-lo]; - //adjust code from 'merge' here so that the part of a from lo to mid, and the part of a from mid to hi are merged into t - System.arraycopy(t, 0, a, lo, hi-lo) //copy back into a - - } - - -``` - -## 4 Complexity - -- n is the length of a plus the length of b -- no obvious counter controlled loop -- key ⇒ in each of the three loops mi in incremented by one. - -- ∴ the total number of loop bodies executed is always n -- since each loop has a constant amount of work -- ∴ so total cost is **ϴ(n)** +- so there are no local access advantages \ No newline at end of file diff --git a/content/notes/08-mergesort-2.md b/content/notes/08-mergesort-2.md index a4f2433e7..6b023e68d 100644 --- a/content/notes/08-mergesort-2.md +++ b/content/notes/08-mergesort-2.md @@ -1,110 +1,11 @@ --- title: "08-mergesort-2" +sr-due: 2022-04-06 +sr-interval: 8 +sr-ease: 270 tags: - cosc201 - lecture --- -recall definition of merge sort -- pre ⇒ split -- rec ⇒ sort pieces -- post ⇒ merge - -## 1 Complexity - -no counters - -pre and post pahses are constant and ϴ(n) - -so M(n) = ϴ(n) + 2 * M(n/2) - -does this even help. what if n is odd - -pretend ϴ(n) is $C \times n$ - -$$ -\begin{align*} -M(n) &= C \times n+2 \times M(n/2) \\ -&= C \times n+2 \times (C \times (n/2) + 2 \times M(n/4))\\ -&= C \times (2n) + 4 \times M(n/4) \\ -&= C \times (2n) + 4 \times (C \times (n/4)) + 2 \times M(n/8))\\ -&= C \times (3n) + 8 \times M(n/8)\\ \\ -&= C \times (kn) + 2^k \times M(n/2^k) -\end{align*} -$$ - -ends when we find base case -when we get to $n/2^k = 1$ -we could split earlier. -the work done base case is (bounded by) some constatn D -so if $k$ is large enough that $n/2^k$ is a base case, we get - -$$ -M(n) = C \times (kn) + 2^k \times D -$$ - -how big is $k$ - -$k <=lg(n)$ - -so: -$$ -M(n) ≤ C \times (n lg(n)) + D(n) = ϴ(n lg(n)) -$$ - -which is true - -> In a divide and consiwer algo wher pre and pst processign work are Ο(n) and the division is into parts of size at least n for some contatn c > 0 tge total time complexity is Ο(n lg n) and generally ϴ(n log n) - -## 2 Variations of mergesort - -unite and conquer - -5 | 8 | 2 | 3 | 4 | 1 | 7 | 6 - -5 8 | 2 3 | 1 4 | 6 7 - -2 3 5 8 | 1 4 6 7 - -1 2 3 4 5 6 7 8 - -```java - public static void mergeSort(int[] a) { - int blockSize = 1; - while(blockSize < a.length) { - int lo = 0; - while (lo + blockSize < a.length) { - int hi = lo + 2*blockSize; - if (hi > a.length) hi = a.length; - merge(a, lo, lo + blockSize, hi); - lo = hi; - } - blockSize *=2; - } - } - -``` - -outer loop is executed lg n times, where n is the length of a - -inner loop proceeds until we find a block that "runs out of elements" - -inner loop is having 2 x blocksize added each time, to runs most n/2 x blocksize - -inside inner is call to merge which is ϴ(blocksize) - - -### 2.1 complexity from bottom up - -- $n$ is the numbe of elemetns in a -- outer loop is executed - -![[Pasted image 20220329114859.png#invert]] - -### 2.2 improvments -some arrays have sections that are already sorted - -you canm - -### 2.3 timsort -used by python java rust etc +[mergeosrt](notes/mergeosrt.md) diff --git a/content/notes/cosc-201-lectures.md b/content/notes/cosc-201-lectures.md index 9fe57972f..bd9f117ff 100644 --- a/content/notes/cosc-201-lectures.md +++ b/content/notes/cosc-201-lectures.md @@ -6,7 +6,7 @@ tags: --- links: [[notes/cosc-201]] -- [[notes/07-mergesort-1]] -- [[notes/08-mergesort-2]] -- [[notes/09-stacks-and-queues]] -- [[notes/10-heaps-and-heapsort]] \ No newline at end of file +- [07-mergesort-1](notes/07-mergesort-1.md) +- [08-mergesort-2](notes/08-mergesort-2.md) +- [09-stacks-and-queues](notes/09-stacks-and-queues.md) +- [10-heaps-and-heapsort](notes/10-heaps-and-heapsort.md) \ No newline at end of file diff --git a/content/notes/mergeosrt.md b/content/notes/mergeosrt.md new file mode 100644 index 000000000..9741b8200 --- /dev/null +++ b/content/notes/mergeosrt.md @@ -0,0 +1,156 @@ +--- +title: "mergesort" +tags: +- cosc201 +- algorithm +--- + +Mergesort is a [divide-and-conquer](notes/divide-and-conquer.md) algorithm. It works by recursively splitting the array in half then merging the two (sorted) halfs together . It has three main steps. These are: + +- pre-processing: split the array into two pieces +- recurive step: sort each of the pieces +- post-processing: merge the two pieces + +e.g., + +7 5 3 9 1 8 2 5 4 0 + +7 5 3 9 1 | 8 2 5 4 0 + +7 5 | 3 9 1 | 8 2 5 | 4 0 + +5 7 | 1 9 3 | 2 8 5 | 0 4 + +1 3 5 7 9 | 0 2 4 5 8 + +0 1 2 3 4 4 6 7 8 9 + +# 1 Implementation + +## 1.1 Merge + +Given: a and b are sorted arrays. m is an array whose size is the sum of their sizes +Get: a sorted array containing the elements of a and b + +Keep track of indices, ai, bi, and mi of the active location of a, b, and m. +Find which of ai or bi is lesser (break ties is favour of a), and copy that value into m at mi, and increment mi and whichever of ai or bi was used. +Once ai or bi is out of range, copy the rest of the other array into the remainder of m + +```java +public static int[] merge (int[] a int[] b){ + int[] m = new int[a.length + b.length] + int ai = 0, bi = 0, mi = 0; + + while(ai < a.length && bi < b.length) { + if(a[ai] <= b[bi]) m[mi++] = a[ai++]; + else m[mi++] = b[bi++] + } + + while (ai < a.length) m[mi++] = a[ai++]; + while (bi < b.length) m[mi++] = a[bi++]; + + return m; +} +``` + + +### 1.1.1 Complexity of merge + +$\theta(n)$ + +$n$ is the sum of the lengths of $a$ and $b$ + +Each time we loop the parameter $mi$ must increase by one, and this parameter runs from $0$ to $n-1$ + +Since the total number of loop bodies executed is $n$ and each loop does a constant amount of work, the total time complexity is $\theta(n)$ + + +## 1.2 Sort + +```java +public static void mergeSort(int[] a) { + int blockSize = 1; + while (blockSize < a.length) { + int lo = 0; + while (lo + blockSize < a.length) { + int hi = lo + 2*blockSize; + if (hi > a.length) hi = a.length; + merge(a, lo, lo + blockSize, hi); + lo = hi; + } + blockSize *= 2; + } +} +``` + + +### 1.2.1 Complexity of Sort + +$\theta(n\ lg\ n)$ + +> In a divide and conquer algorithm where pre and pst processing work are Ο(n) and the division is into parts of size at least n for some contatn c > 0 the total time complexity is Ο(n lg n) and generally ϴ(n log n) + +#### 1.2.1.1 Top down + +We can split into the three steps to analyse this. + +- Pre has constant time i.e., $\theta(1)$ +- Post has linear time i.e., $\theta(n)$ + +Therefore: $M(n) = \theta(n) + 2 \times M(n/2))$ + +Substitue $\theta(n)$ with $C \times n$ then + +$$ +\begin{align*} +M(n) &= C \times n+2 \times M(n/2) \\ +&= C \times n+2 \times (C \times (n/2) + 2 \times M(n/4))\\ +&= C \times (2n) + 4 \times M(n/4) \\ +&= C \times (2n) + 4 \times (C \times (n/4)) + 2 \times M(n/8))\\ +&= C \times (3n) + 8 \times M(n/8)\\ \\ +&= C \times (kn) + 2^k \times M(n/2^k) +\end{align*} +$$ + +This stops (at least) when we reach the base case of $n/2^k=1$ . We could stop earlier and + +If we do a constant amount of work $D$ when we reach the base case we get: + +$$ +M(n) = C \times (kn) + 2^k \times D +$$ + +where $k\leq lg(n)$ so: + +$$ +M(n) ≤ C \times (n lg(n)) + D(n) = ϴ(n\ lg(n)) +$$ + + + + + +#### 1.2.1.2 Bottom Up + +- Let n be the number of elements in the array, $a$. +- The outer while loop (controlled by blockSize, or $b$) is executed $lg(n)$ times since its upper bound is n and b is doubled each time. +- In the inner loop, the update on lo is to add $2b$ so it is executed $n/(2b)$ times. +- The inner loop merges two arrays of size b, so each instance does $\theta(b)$ work. +- That gives an upper bound on the work done in one instance of the outer loop of the form: + +$$ +(n/(2b)) \times (A \times b) = (A/2) \times n +$$ + +and a matching lower bound. + + +- Thus, the work done in one instance of the outer loop is $\theta(n)$ +- And so, the total complexity is $\theta(n\ lg\ n)$. + +The bottom-up version does exactly the same thing as the top-down version, just in an apparently different order, so this analysis applies to the top-down version as well. + + +# 2 Variations of Mergesort + +[[unite and conquer]] #unfinished diff --git a/content/notes/unite-and-conquer.md b/content/notes/unite-and-conquer.md new file mode 100644 index 000000000..3b3fdcbef --- /dev/null +++ b/content/notes/unite-and-conquer.md @@ -0,0 +1,56 @@ +--- +title: "unite-and-conquer" +tags: +- cosc201 +--- + +unite and conquer + +5 | 8 | 2 | 3 | 4 | 1 | 7 | 6 + +5 8 | 2 3 | 1 4 | 6 7 + +2 3 5 8 | 1 4 6 7 + +1 2 3 4 5 6 7 8 + +```java + public static void mergeSort(int[] a) { + int blockSize = 1; + while(blockSize < a.length) { + int lo = 0; + while (lo + blockSize < a.length) { + int hi = lo + 2*blockSize; + if (hi > a.length) hi = a.length; + merge(a, lo, lo + blockSize, hi); + lo = hi; + } + blockSize *=2; + } + } + +``` + +outer loop is executed lg n times, where n is the length of a + +inner loop proceeds until we find a block that "runs out of elements" + +inner loop is having 2 x blocksize added each time, to runs most n/2 x blocksize + +inside inner is call to merge which is ϴ(blocksize) + + +### 0.1.1 complexity from bottom up + +- $n$ is the numbe of elemetns in a +- outer loop is executed + +![[Pasted image 20220329114859.png#invert]] + +### 0.1.2 improvments +some arrays have sections that are already sorted + +you canm + +### 0.1.3 timsort +used by python java rust etc