├── README.pdf ├── img ├── BigO.png ├── JCF.png ├── Treap.png ├── graph.png ├── 24Tree.png ├── ArrayQueue.png ├── ArrayStack.png ├── BinaryHeap.png ├── BinaryTree.png ├── HashTable.png ├── LinkedList.png ├── RedBlack.png ├── Scapegoat.png ├── RootishArray.png ├── AddingRedNode.png ├── DualArrayDeque.png ├── SSetInterface.png └── DoublyLinkedList.png ├── Final Review.pdf ├── Summary Tables.pdf ├── midterm review.pdf ├── notes on zip files.pdf ├── Data Structures Summary.pdf ├── Final Review Questions.pdf ├── Sorting Algorithms Summary.pdf ├── notes on zip files.md ├── midterm review.md ├── Summary Tables.md ├── Sorting Algorithms Summary.md ├── Data Structures Summary.md ├── README.md └── Final Review.md /README.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/README.pdf -------------------------------------------------------------------------------- /img/BigO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/BigO.png -------------------------------------------------------------------------------- /img/JCF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/JCF.png -------------------------------------------------------------------------------- /img/Treap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/Treap.png -------------------------------------------------------------------------------- /img/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/graph.png -------------------------------------------------------------------------------- /img/24Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/24Tree.png -------------------------------------------------------------------------------- /Final Review.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/Final Review.pdf -------------------------------------------------------------------------------- /Summary Tables.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/Summary Tables.pdf -------------------------------------------------------------------------------- /img/ArrayQueue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/ArrayQueue.png -------------------------------------------------------------------------------- /img/ArrayStack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/ArrayStack.png -------------------------------------------------------------------------------- /img/BinaryHeap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/BinaryHeap.png -------------------------------------------------------------------------------- /img/BinaryTree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/BinaryTree.png -------------------------------------------------------------------------------- /img/HashTable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/HashTable.png -------------------------------------------------------------------------------- /img/LinkedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/LinkedList.png -------------------------------------------------------------------------------- /img/RedBlack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/RedBlack.png -------------------------------------------------------------------------------- /img/Scapegoat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/Scapegoat.png -------------------------------------------------------------------------------- /midterm review.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/midterm review.pdf -------------------------------------------------------------------------------- /img/RootishArray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/RootishArray.png -------------------------------------------------------------------------------- /img/AddingRedNode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/AddingRedNode.png -------------------------------------------------------------------------------- /img/DualArrayDeque.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/DualArrayDeque.png -------------------------------------------------------------------------------- /img/SSetInterface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/SSetInterface.png -------------------------------------------------------------------------------- /notes on zip files.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/notes on zip files.pdf -------------------------------------------------------------------------------- /img/DoublyLinkedList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/img/DoublyLinkedList.png -------------------------------------------------------------------------------- /Data Structures Summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/Data Structures Summary.pdf -------------------------------------------------------------------------------- /Final Review Questions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/Final Review Questions.pdf -------------------------------------------------------------------------------- /Sorting Algorithms Summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riconaranjo/COMP-2402/HEAD/Sorting Algorithms Summary.pdf -------------------------------------------------------------------------------- /notes on zip files.md: -------------------------------------------------------------------------------- 1 | # How to Zip Files Using Terminal in COMP 2402 2 | 3 | Use the zip command in the terminal when in the root assignment folder: 4 | 5 | zip -r new_folder.zip folder_1 folder_2 -x "*.DS_Store" "*.class" 6 | 7 | This will zip `folder_1` and `folder_2` and their contents [recursively, `-r` command] into a zip file named `new_folder.zip`. 8 | 9 | The zip command will compress without the `__MACOSX` folder, which is added when using the system compressing tool. The `*.DS\_Store` and `*.class` arguements are added after the `-x` command to ignore all files that have these file extensions. 10 | 11 | ## Compiling Java Using Terminal 12 | 13 | This command will comiple the java file and output any compilation errors. 14 | 15 | javac PartX.java 16 | 17 | ## Running Java Programs Using Terminal 18 | 19 | ### Assignment 1 20 | 21 | This command will run the compiled Java code, take the `testX-01.in` file as input and write to the `testX-01.in` file [replace X with part number]. 22 | 23 | java comp2402a1.PartX tests/testX-01.in tests/testX-01.out 24 | 25 | ### For copying and pasting 26 | 27 | javac Part10.java 28 | 29 | java comp2402a1.Part10 tests/test10-01.in tests/test10-01.out 30 | 31 | zip -r comp2402a1.zip comp2402a1 tests -x "*.DS_Store" "*.class" -------------------------------------------------------------------------------- /midterm review.md: -------------------------------------------------------------------------------- 1 | # Midterm Review 2 | 3 | ## 1 - Quickest contains 4 | 5 | - Set is fastest to find is an element exists 6 | - Collection is an abstract class 7 | 8 | ## 2 - Quickest find 9 | 10 | - SortedSet, if you store a string `({lastname},{firstname})` 11 | 12 | ## 5 - ArrayList 13 | 14 | - get() is O(1) in ArrayList 15 | - remove() in O(1 + n-i) 16 | 17 | ## 6 - Linked List 18 | 19 | ## 7 - ArrayList vs LinkedList 20 | 21 | - Same because from front of array 22 | 23 | ## 8 - ArrayList vs LinkedList 24 | 25 | - ArrayList is faster at random locations 26 | 27 | 28 | ## 9 - ArrayList vs LinkedList 29 | 30 | - same at the back 31 | 32 | ## 10 - ArrayList vs LinkedList 33 | 34 | - ArrayList has to shift all elements 35 | - LinkedList is faster 36 | 37 | ## 11 - ArrayList vs LinkedList 38 | 39 | - same since in the middle? 40 | 41 | ## 12 - ArrayList vs LinkedList 42 | 43 | - LinkedList is faster since we have pointer to middle 44 | - Don't need to iterate to get to middle 45 | 46 | ## 13 - ArrayStack 47 | 48 | - simple math 49 | 50 | ## 14 - ArrayStack 51 | 52 | - a.length/2 - a.length/3 = a.length/6 53 | - 3n < a.length 54 | - n < a.length/3 55 | - thus, (a.length/6) / (a.length/3) = n / 2 56 | 57 | ## 15 - ArrayStack 58 | 59 | - memorize `At most 2m elements are copied by grow() and shrink()` 60 | 61 | ## 16 - ArrayDequq 62 | 63 | - O(1+min{i,n−i}) 64 | 65 | ## 17 - Binary 66 | 67 | ## 18 - Binary 68 | 69 | - x%m is same as x&(m-1) 70 | 71 | ## 19 - DualArrayDeque 72 | 73 | - front arraydeque is reversed 74 | 75 | ## 21 - RootishArrayStack 76 | 77 | - 10 * 11/2 78 | 79 | ## 22 - RootishArrayStack 80 | 81 | - get(3)[4]; 82 | 83 | ## 23 - SinglyLinkedList (SLL) as a Queue 84 | 85 | - enqueue is add tail 86 | - dequeue is remove head 87 | 88 | ## 24 - SinglyLinkedList (SLL) as a Stack 89 | 90 | - push is add head 91 | - pop is remove head 92 | 93 | ## 25 - SLL 94 | 95 | - in O(1 + min(i, n(n − i − 1)) time 96 | - This catches the condition when head == tail 97 | - i.e. if i = n-1 => n(n − i − 1) becomes 0 98 | 99 | ## 26 - DLL 100 | 101 | - dummy node is used to point to front and back 102 | - dummy.next is front 103 | - dummy.prev is back 104 | 105 | ## 28 - DLL 106 | 107 | - add() in O(1 + min(i, n−i) 108 | - remove() in O(1 + min(i, n−i)) 109 | 110 | ## 29 - HashTable [HashMap] 111 | 112 | - O(n/m) 113 | - Elements are evenly spaced out -------------------------------------------------------------------------------- /Summary Tables.md: -------------------------------------------------------------------------------- 1 | # Summary Tables 2 | 3 | These are all the tables summarizing the comparisons between different data structures and algorithms covered in this course. 4 | 5 | ## Access and Modifification Characteristics 6 | 7 | | | get/set | add/remove | 8 | |------------|---------------------|---------------------| 9 | | Arrays | _O(1)_ | _O(1 + min(i,n-i))_ | 10 | | LinkedList | _O(1 + min(i,n-i))_ | _O(1)`*`_ | 11 | | Skiplist | _O(log n)_ | _O(log n)_ | 12 | 13 | `*given a pointer to the location, else traversal is necessary` 14 | 15 | ## Binary Search Tree Implementations 16 | 17 | | | find() | add() | remove() | 18 | |------------------|------------------------|------------------------|------------------------| 19 | | BST | _O(n)_ | _O(n)_ | _O(n)_ | 20 | | RBST / Treaps | _O(log n)_ [expected] | _O(log n)_ [expected] | _O(log n)_ [expected] | 21 | | Scapegoat Trees | _O(log n)_ [amortized] | _O(log n)_ [amortized] | _O(log n)_ [amortized] | 22 | | 2-4 / RedBlack Trees | _O(log n)_ [worst-case] | _O(log n)_ [worst-case] | _O(log n)_ [worst-case] | 23 | 24 | ## Sorted Set Implementations 25 | 26 | | | Runtime | 27 | |--------------------------|-------------------------| 28 | | Skiplists | _O(log n)_ [expected] | 29 | | Treaps | _O(log n)_ [expected] | 30 | | Scapegoat Trees | _O(log n)_ [amortized] | 31 | | **2-4 / RedBlack Trees** | _O(log n)_ [worst-case] | 32 | 33 | ## Comparison-based Algorithms 34 | 35 | | | Comparisons | In-place | Stable | 36 | |------------|----------------------------------|----------|--------| 37 | | Merge Sort | _n•log(n)_ [worst-case] | no | yes | 38 | | Heap Sort | _1.38n•log(n) + O(n)_ [expected] | yes | no | 39 | | Quick Sort | _2n•log(n) + O(n)_ [worst-case] | yes | no | 40 | 41 | ## Graph Implementations 42 | 43 | | | Adjacency Matrix | Adjacency List | 44 | |------------|---------------------|---------------------| 45 | | addEdge | _O(1)_ | _O(1)_ | 46 | | removeEdge | _O(1)_ | _O(deg(i))_ | 47 | | hasEdge | _O(1)_ | _O(deg(i))_ | 48 | | outEdge | _O(n)_ | _O(1)_ | 49 | | inEdge | _O(n)_ | _O(n+m)_ | 50 | | | | | 51 | | space used | _O(n^2)_ | _O(n+m)_ | 52 | 53 | ## Adjacency Matrix vs. Adjacency List 54 | 55 | It is better to use **Adjacency List** for **traversals**. 56 | 57 | | | Adjacency Matrix | Adjacency List | 58 | |------------|---------------------|---------------------| 59 | | Breadth | _O(n^2)_ | _O(n+m)_ | 60 | | Depth | _O(n^2)_ | _O(n+m)_ | -------------------------------------------------------------------------------- /Sorting Algorithms Summary.md: -------------------------------------------------------------------------------- 1 | # Sorting Algorithms Summary 2 | 3 | **In-place:** means modifying list to be sorted [as opposed to returning new sorted list]. 4 | **Stable:** means the order of elements with equal values is preserved. 5 | 6 | ## Lower bound on Comparion-based Sorting 7 | 8 | For a comparion-based algorithm, the expected number of comparions is Ω(n•log(n)). 9 | 10 | ## Merge Sort 11 | 12 | Sort list by merging sorted sub-lists, reduces total number of comparisons needed. 13 | 14 | 1. Divide list into equally sized halves until 1 element per sub-list 15 | 2. Sort sub-list [recursively] 16 | 3. Merge sub-list using comparator 17 | 18 | - Comparison-based 19 | - **Not in-place** 20 | - **Stable** 21 | - **Runs in O(n•log(n)) time** 22 | 23 | `// performs at most n•log(n) comparisons` 24 | 25 | ## Heap Sort 26 | 27 | Sort by traversing down a heap tree. 28 | 29 | 1. Create a heap from list 30 | 2. Delete the root node [in list, a[n-1]] 31 | - Now root is in a[n], since n-- 32 | 3. Heapify [make sure heap property is preserved] 33 | 4. Repeat steps 2-4 until no more elements to sort 34 | 35 | - Comparison-based 36 | - **In-place** 37 | - **Not stable** 38 | - **Runs in O(n•log(n)) time** 39 | 40 | `// performs at most 2n•log(n) + O(n) comparisons` 41 | 42 | ## Quick Sort 43 | 44 | Sort using a randomly selected value as partition point, sorting sub-lists.
45 | Since random selection, might choose worst value [ideally middle value]. 46 | 47 | 1. Randomly select value 48 | 2. Add all values less than to left sub-list, otherwise add to right sub-list 49 | 3. Repeat until 1 element in sub-list 50 | 51 | - Comparison-based 52 | - **In-place** 53 | - **Not stable** 54 | - **Runs in O(n•log(n)) [expected] time** 55 | 56 | `// performs at most 2n•log(n) + O(n)` 57 | 58 | ### Comparison-based Algorithms 59 | 60 | | | Comparisons | In-place | Stable | 61 | |------------|------------------------------------|----------|--------| 62 | | Merge Sort | _n•log(n)_ [worst-case] | no | yes | 63 | | Heap Sort | _1.38n•log(n) + O(n)_ [worst-case] | yes | no | 64 | | Quick Sort | _2n•log(n) + O(n)_ [expected] | yes | no | 65 | 66 | **Merge Sort:** 67 | 68 | - Fewest comparisons 69 | - Does not rely on randomization [guaranteed runtime] 70 | - Not in-place [expensive memory usage] 71 | - Stable 72 | - Much better at sorting a linked list 73 | - no additional memory is needed with pointer manipulation 74 | 75 | **Quick Sort:** 76 | 77 | - Second fewest comparisons 78 | - Randomized [expected runtime] 79 | - In-place [memory efficient] 80 | - Not stable 81 | 82 | **Heap Sort:** 83 | 84 | - Most comparisons 85 | - Not randomized [guaranteed runtime] 86 | - In-place [memory efficient] 87 | - Not stable 88 | 89 | ## Counting Sort 90 | 91 | Counting array is used to keep track of duplicates; it is then used to construct the sorted list. 92 | 93 | - Not comparison-based 94 | - **Not in-place** 95 | - **Not stable** 96 | - **Runs in O(n+k) time** 97 | - n integers 98 | - range of 0...k 99 | 100 | `// efficient for integers when the length is roughly equal to maximum value k-1` 101 | 102 | ## Radix Sort 103 | 104 | Sorts w-bit integer with counting sort on d-bits per integer [least to most significant] 105 | 106 | - Not comparison-based 107 | - **Not in-place** 108 | - **Not stable** 109 | - **Runs in O(c•n) time** 110 | - n w-bit integers 111 | - range of 0...(n^c - 1) -------------------------------------------------------------------------------- /Data Structures Summary.md: -------------------------------------------------------------------------------- 1 | # Data Structure Summary 2 | 3 | A data structure is an implementation of an [abstract] interface. 4 | 5 | - List 6 | - Queue 7 | - Stack 8 | - Deque [double ended queue] 9 | - Unordered Set [set] 10 | - Sorted Set 11 | - Map [set of key-value pairs] 12 | - Sorted Map [sorted set of key-value pairs (kvp)] 13 | 14 | ## Access and Modifification Characteristics 15 | 16 | | | get/set | add/remove | 17 | |------------|---------------------|---------------------| 18 | | Arrays | _O(1)_ | _O(1 + min(i,n-i))_ | 19 | | LinkedList | _O(1 + min(i,n-i))_ | _O(1)`*`_ | 20 | | Skiplist | _O(log n)_ | _O(log n)_ | 21 | 22 | `*given a pointer to the location, else traversal is necessary` 23 | 24 | ## Set 25 | 26 | Efficient for contains(). 27 | 28 | ## SortedSet 29 | 30 | Efficient for find(). 31 | 32 | - Does a successor search [closest value ≥ to value] 33 | 34 | ## Maps 35 | 36 | Efficient for contains() [kvp] 37 | 38 | ## SortedMap 39 | 40 | Efficient for find() [kvp] 41 | 42 | ## Array-based 43 | 44 | Efficient for read / write. 45 | Expensive insertion / deletion. 46 | 47 | ### ArrayList / ArrayStack 48 | 49 | Efficient access anywhere. 50 | Efficient insertion / deletion at back [think stack]. 51 | 52 | - Implements **List** interface with an array 53 | - superceded by ArrayDeque 54 | - **get(), set() in O(1)** 55 | - **add(), remove() in O(1 + n-i)** 56 | - **resize is O(n)** [amortized] 57 | 58 | `// for m ≥ 1 add() / remove() calls, resize() will copy at most 2m` 59 | 60 | `// the amortized cost of resize() for m calls is 2m/m = O(1)` 61 | 62 | ![array-stack](img/ArrayStack.png) 63 | 64 | ### ArrayQueue / ArrayDeque 65 | 66 | Efficient access anywhere. 67 | Efficient insertion / deletion at front and back [think deque]. 68 | 69 | - Implements **List** interface with an array 70 | - **get(), set() in O(1)** 71 | - **add(), remove() in O(1 + min(i, n-i))** 72 | - **resize is O(n)** [amortized] 73 | 74 | `// since ArrayQueue only supports addLast() and removeFirst(), these are O(1)` 75 | 76 | ![array-queue](img/ArrayQueue.png) 77 | 78 | ### DualArrayDeque 79 | 80 | Efficient access anywhere. 81 | Efficient insertion / deletion at front and back [think deque]. 82 | 83 | - Implements **List** interface 84 | - Uses two **ArrayStacks** front-to-front 85 | - May be rebalanced if one array is much larger than the other 86 | - **get(), set() in O(1)** 87 | - **add(), remove() in O(1 + min(i, n-i))** 88 | 89 | ![dual-array-deque](img/DualArrayDeque.png) 90 | 91 | ### RootishArrayStack 92 | 93 | List of Lists, of increasing size. 94 | Efficient space [sqrt(n) wasted space. 95 | Efficient access anywhere. 96 | Efficient insertion / deletion at back. 97 | 98 | - Implements the **List** interface using multiple backing arrays 99 | - Reduces 'wasted space' [unused space] 100 | - At most: _sqrt(n)_ unused array locations 101 | - Good for space efficiency 102 | - **get(), set() in O(1)** 103 | - **add(), remove() in O(1 + n-i)** 104 | 105 | `// m ≥ 1 add() / remove() calls, results on O(m) time on resize()` 106 | 107 | ![rootish-array](img/RootishArray.png) 108 | 109 | ## Linked Lists 110 | 111 | Efficient insertion / deletion. 112 | Expensive access. 113 | 114 | ### Singly Linked List [SLList] 115 | 116 | Nodes with pointer to next node. 117 | Efficient insertion / deletion. 118 | Expensive access. 119 | 120 | - Implements the Stack and Queue **interfaces**. 121 | - **get(), set() in O(1 + i)** 122 | - **add(), remove() in O(1)** 123 | 124 | ![linked-list](img/LinkedList.png) 125 | 126 | ### Doubly Linked List [DLList] 127 | 128 | Nodes with pointers to previous and next nodes. 129 | Efficient insertion / deletion. 130 | Expensive access. 131 | 132 | - Implements the Stack and Queue **interfaces**. 133 | - **get(), set() in O(1 + min(i, n-i))** 134 | - **add(), remove() in O(1 + min(i, n-i))** 135 | 136 | ![doubly-linked-list](img/DoublyLinkedList.png) 137 | 138 | ### SELList [Space-Efficient Linked List] 139 | 140 | Nodes with pointers to previous and next nodes. 141 | Values stored as blocks in each node. [you can skip data] 142 | Efficient insertion / deletion. 143 | Expensive access. 144 | 145 | - Implements the **List** interfaces 146 | - wasted space: { n + O(b + n/b) } 147 | - **get(), set() in O(1 + min(i, n-i)/_b_)** 148 | - **add(), remove() in O(1 + min(i, n-i)/_b_)** 149 | 150 | `// m ≥ 1 add() / remove() calls, results in O(b•m) time on resize()` 151 | 152 | ## SkipLists 153 | 154 | SLL with additional skipping pointers. 155 | Randomly generated structure. 156 | Allows for faster searches. 157 | 158 | - Implements the **SortedSet** interface 159 | - Successor search: **find(x) will return smallest value ≥ x** 160 | - **get(), set() in O(log n)** 161 | - **add(), remove() in O(log n)** 162 | 163 | ![sset-interface](img/SSetInterface.png) 164 | 165 | ## **After Midterm** 166 | 167 | ## HashTable 168 | 169 | - Unordered sets with fast access 170 | - Associative array 171 | - Index elements into a range of int 172 | - for non-integer elements, use hashCode() 173 | 174 | ![hash-table](img/HashTable.png) 175 | 176 | ### ChainedHashTable 177 | 178 | - Implements the **USet** interface 179 | - **find(), add(), remove() in O(n_i)** 180 | - where *n_i* is based of size of list at index 181 | 182 | `// m ≥ 1 add() / remove() calls, results in O(m) time on resize()` 183 | 184 | ## Binary Tree 185 | 186 | - Nodes with up to two child nodes 187 | 188 | ![binary-tree](img/BinaryTree.png) 189 | 190 | ### Binary Search Tree [BST] 191 | 192 | - Implements the **SSet** interface 193 | - **find(), add(), remove() in O(n)** 194 | 195 | ### Random Binary Search Trees [RBST] 196 | 197 | Balanced trees are statistically more likely 198 | 199 | - Implements the **SSet** interface 200 | - **contructed in O( n•log(n) )** 201 | - ** in O(n)** 202 | - **find(), add(), remove() in O(log n)** 203 | 204 | `// search path is at most 2•log(n) + O(1)` 205 | 206 | ### Treaps 207 | 208 | **Has an extra priority:**
209 | Parent priority should be less than child priority.
210 | This has the property of bounding the height of the tree. 211 | 212 | - Implements the **SSet** interface 213 | - Priorities are randomly applied 214 | - **contructed in O( n•log(n) )** 215 | - **find(), add(), remove() in O(log n)** 216 | 217 | ![treap](img/Treap.png) 218 | 219 | ### Scapegoat Tree 220 | 221 | BST that with height maintained within O(log n), rebuilt if too unbalanced.
222 | Limited with integer q, where height ≤ log_{3/2}(q) 223 | 224 | - Implements the **SSet** interface 225 | - Rebuild only one search path that triggered rebuild 226 | - this ensures that not entire tree is rebuilt 227 | - **rebuild() in O(log n) amortized** 228 | - **find(), add(), remove() in O(log n)** 229 | 230 | ![scapegoat](img/Scapegoat.png) 231 | 232 | `// m calls to add() / remove (), results in O( m•log(n) time spent on rebuild()` 233 | 234 | ### 2-4 Tree 235 | 236 | Tree where every leaf has the same depth. 237 | 238 | - Implements the **SSet** interface 239 | - All leaves have equal depth 240 | - All internal nodes have 2-4 children 241 | - **find(), add(), remove() in O(log n) [worst-case]** 242 | 243 | ![24Tree](img/24Tree.png) 244 | 245 | ### RedBlack Tree 246 | 247 | A self-balancing binary search tree, built off a 2-4 Tree, where each node has a 'colour'. 248 | 249 | - Implements the **SSet** interface 250 | - Uses colour to remain balanced when adding / removing 251 | - There is the same number of black nodes on every root to leaf path 252 | - i.e. equal sum of colours on any root to leaf path 253 | - No red nodes can be adjacent 254 | - red nodes must have black parent 255 | - left-leaning: if left node is black, then right node must be black 256 | - **Maximum height of 2•log(n)** 257 | - **find(),add(), remove() in O(log n) [worst-case]** 258 | 259 | ## Binary Search Tree Implementations 260 | 261 | | | find() | add() | remove() | 262 | |------------------|------------------------|------------------------|------------------------| 263 | | BST | _O(n)_ | _O(n)_ | _O(n)_ | 264 | | RBST / Treaps | _O(log n)_ [expected] | _O(log n)_ [expected] | _O(log n)_ [expected] | 265 | | Scapegoat Trees | _O(log n)_ [amortized] | _O(log n)_ [amortized] | _O(log n)_ [amortized] | 266 | | 2-4 / RedBlack Trees | _O(log n)_ [worst-case] | _O(log n)_ [worst-case] | _O(log n)_ [worst-case] | 267 | 268 | ### Sorted Set Implementations 269 | 270 | | | Runtime | 271 | |--------------------------|-------------------------| 272 | | Skiplists | _O(log n)_ [expected] | 273 | | Treaps | _O(log n)_ [expected] | 274 | | Scapegoat Trees | _O(log n)_ [amortized] | 275 | | **2-4 / RedBlack Trees** | _O(log n)_ [worst-case] | 276 | 277 | ## Binary Heaps 278 | 279 | A complete Binary Tree that also maintains the heap property. 280 | 281 | - Implements the [priority] **Queue Interface** 282 | - Allows to find / remove most extreme node with peek() / remove() 283 | - **add(), remove() in O(log n)** 284 | - **peek() in O(1)** 285 | 286 | ![binary-heap](img/BinaryHeap.png) 287 | 288 | `// m ≥ 1 add() / remove() calls, results in O(m) time on resize()` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # COMP 2402 Class Notes 2 | 3 | ## Java Collections Framework (JCF) 4 | 5 | The Java Collections Framework (JCF) is a unified architecture for representing and manipulating collections. 6 | 7 | _A collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data. Typically, they represent data items that form a natural group, such as a poker hand (a collection of cards), a mail folder (a collection of letters), or a telephone directory (a mapping of names to phone numbers). If you have used the Java programming language — or just about any other programming language — you are already familiar with collections._ 8 | 9 | In order to use the JCF you can import it like this. 10 | 11 | ```java 12 | import java.util.* 13 | ``` 14 | 15 | ## Sorting 16 | 17 | This is how to sort strings based on length by using anonymous object [**Comparator**]. 18 | 19 | ``` java 20 | Collections.sort(list, new Comparator() { 21 | public int compare(String x, String y) { 22 | return x.length() - y.length(); 23 | } 24 | }); 25 | 26 | // or you can use lambda function 27 | list.sort( (String o1, String o2) -> o1.compareTo(o2) ); 28 | 29 | // if you want to sort by length and also alphabetically 30 | Collections.sort(list,new Comparator() { 31 | public int compare(String x, String y) { 32 | // if not same length, use length 33 | if(x.length() != y.length()) { 34 | return x.length() - y.length(); 35 | } 36 | // else compare as strings 37 | return x.compareTo(y); 38 | } 39 | }); 40 | ``` 41 | 42 | The **compare(x,y)** method works by moving an element left if the **compare(x,y)** method returns a negative integer, and moves the element right if the **compare(x,y)** returns a positive integer. [difference between x and y] 43 | 44 | (-) x < y 45 | (0) x = y 46 | (+) x > y 47 | 48 | ## Maps [Hashmap] 49 | 50 | Also known as dictionaries in Swift or C#... 51 | 52 | - Cannot have duplicate entries 53 | 54 | ``` java 55 | Map map = new HashMap<>(); 56 | map.put("Java", 6); 57 | map.put("Swift", 10); 58 | map.put("C#", 7); 59 | map.put("Ruby", 9); 60 | 61 | // this will print out every value in the map [foreach] 62 | for(String str : map.keySet()) { 63 | System.out.println(str + " : " + map.get(str)) 64 | } 65 | 66 | map.get(key); // fast operation, returns null if no key found 67 | ``` 68 | 69 | ## List 70 | 71 | Continuing from previous example... 72 | 73 | **Map.Entry** is just a key-value pair 74 | 75 | ``` java 76 | List> entryList = new ArrayList<>(); 77 | entryList.addAll(map.entrySet); // set containing all the elements 78 | 79 | for(Map.Entry entry : entrylist) { 80 | System.out.println(entry.getKey() + " : " + entry.getValue() ); 81 | } 82 | ``` 83 | 84 | ## Deque [ArrayDeque] 85 | 86 | Fast for reading/writing at _start_ or _end_ of list. Basically just a flexible stack/queue. 87 | 88 | ``` java 89 | Deque dq = new ArrayDeque<>(); 90 | dq.addFirst("second"); 91 | dq.addFirst("first"); 92 | dq.addLast("penultimate"); 93 | dq.addLast("last"); 94 | ``` 95 | 96 | ## Priority Queue 97 | 98 | Essentially: uses a heap instead of a tree, in order to keep a certain one on top. 99 | So first element is 'sorted' and then rest is unsorted. 100 | 101 | Not good for sorting, or random access. 102 | 103 | ``` java 104 | Queue pq = new PriorityQueue<>(); 105 | pq.addAll(list); 106 | 107 | System.out.println(pq.remove()); // remove smallest element 108 | ``` 109 | 110 | If alphabetical, one that starts with 'a' will be removed. After first element, the queue is not sorted. Removing one will promote next smallest to the top 111 | 112 | ## Asymptotic Notation [Big O] 113 | 114 | Used to analyze complexity of algorithms, to find faster, or which ones requires more space. 115 | 116 | ### Comparing data structures 117 | 118 | - Time 119 | - Space 120 | - Correctivenes 121 | 122 | ### Growth rates proportioanl to n 123 | 124 | - If input doubles in size, how much will runtime increase? 125 | 126 | ### Runtime as a count of primative operation 127 | 128 | - This is machine independent 129 | - Proportional to exact runtimess 130 | 131 | ``` java 132 | for(int i = 0; i < n; i++) { 133 | arr[i] = i; 134 | } 135 | ``` 136 | 137 | Runtime: 138 | 139 | - **1**: assignment [int i = 0] 140 | - **n+1**: comparisons [i < n] 141 | - **n**: increments [i++] 142 | - **n**: array offset calculations [arr[i]] 143 | - **n**: n indirect assignments [arr[i] = i] 144 | 145 | ### Definition of Big O 146 | 147 | After a certain point, g(x) will grow as fast [or faster] than f(x) 148 | 149 | - g(x) is the upper limit to f(x) 150 | 151 | `O(g(n)) ∀ (f(n) < c•g(n))` 152 | 153 | ### Orders of growth 154 | 155 | | Complexity | Name | 156 | |:-------------|:-------------| 157 | | O(1) | Constant | 158 | | O(log n) | Logarithmic | 159 | | O(n) | Linear | 160 | | O(n•log(n)) | Quasilinear | 161 | | O(n^2) | Quasilinear | 162 | | O(2^n) | Exponential | 163 | | O(n!) | Factorial | 164 | 165 |
166 | 167 | ![big_o](img/BigO.png) 168 | 169 | ### Tips 170 | 171 | - Only largest values matter 172 | - Drop all coefficient 173 | - Log bases are all equivalent 174 | 175 | ### Example 176 | 177 | ``` java 178 | public class BigO { 179 | public static void main() { 180 | String str = ""; 181 | int n = 100; // O(1) 182 | 183 | for(int i = 0; ,< n; i++) { // O(n) 184 | str += "x"; // O(1) but n times 185 | } 186 | 187 | for(int i = 0; i < n; i+=2) { // n/2 times -> O(n) 188 | str += "y" // O(1) 189 | } 190 | 191 | // this is roughly the same as if n was n/2 with O(n) 192 | for(int i = 0; i < n; i*=2) { // O(log n) 193 | str += "y" // O(1) 194 | } 195 | } 196 | } 197 | ``` 198 | 199 | ## Array-based Data Structures 200 | 201 | ### ArrayStack [ArrayList] 202 | 203 | - Implements **List** interface with an array 204 | - Similar to ArrayList 205 | - Efficient only for stack operations [back] 206 | - superceded by ArrayDeque 207 | - **get(), set() in O(1)** 208 | - **add(), remove() in O(1 + n-i)** 209 | - good for write at the back 210 | 211 | ### Stacks vs List 212 | 213 | | Stack | List | 214 | |--------|-------------| 215 | |push(x) |add(n,x) | 216 | |pop() |remove(n-1) | 217 | |size() |size() | 218 | |peek(x) |get(n-1) | 219 | 220 | ### List Interface 221 | 222 | - get(i) / set(i,x) 223 | - Access element i, and return/replace it 224 | - size() 225 | - number of items in list 226 | - add(i,x) 227 | - insert new item x at position i 228 | - remove(i) 229 | - remove the element from position i 230 | 231 | _dereferencing:_ getting the address of a data item 232 | 233 | #### Amortized Cost 234 | 235 | When an algorithm has processes that may be much longer but usually is quick, so you take the average. [roughly] 236 | 237 | e.g. resizing an an array when adding/removing 238 | 239 | ### ArrayQueue & ArrayDeque 240 | 241 | Allow for efficient access at front and backs. 242 | 243 | ![array-queue](img/ArrayQueue.png) 244 | 245 | #### ArrayQueue 246 | 247 | - Implements **Queue** and **List** interfaces with an array 248 | - Cyclic array, (n: number of elements, j: 'index' of last element) 249 | - **get(), set() in O(1)** 250 | - **add(), remove () in O(1 + min(i, n-i))** 251 | - quick to write at front or back 252 | - cannot access anywhere else 253 | - **resize is O(n)** 254 | 255 | #### ArrayDeque 256 | 257 | - Implements **List** interface with an array 258 | - **get(), set() in O(1)** 259 | - **add(), remove() in O(1 + min(i, n-i))** 260 | - quick to write at front or back 261 | - not so quick to access middle 262 | - **resize is O(n)** 263 | 264 | ### DualArrayDeque 265 | 266 | - Implements **List** interface 267 | - Uses two **ArrayStacks** front-to-front 268 | - Since arrays are quick to add to the end, this makes front and back operations fast 269 | - May be rebalanced if one array is much larger than the other 270 | - Use Potential Function to decide when to rebalance 271 | - **get(), set() in O(1)** 272 | - **add(), remove() in O(1 + min(i, n-i))** 273 | - quick to write at front or back, but not middle 274 | 275 | ![dual-array-deque](img/DualArrayDeque.png) 276 | 277 | #### Potential Function 278 | 279 | Define a potential function for the data structure to be the absolute difference of the sizes of the two stacks 280 | 281 | `P = | front_array.size - back_array.size |` 282 | 283 | - Adding or removing an element can only increase/decrease 1 to this function 284 | 285 | ### RootishArrayStack 286 | 287 | - Implements the **List** interface using multiple backing arrays 288 | - Reduces 'wasted space' [unused space] 289 | - At most: _sqrt(n)_ unused array locations 290 | - Good for space efficiency 291 | - **get(), set() in O(1)** 292 | - **add(), remove() in O(1 + n-i)** 293 | - quick to write at the back 294 | 295 | ![rootish-array](img/RootishArray.png) 296 | 297 | ## Linked Lists 298 | 299 | - Recursive data structure made up of nodes 300 | - Pointers to head and tail, and each node points to the next node 301 | - Efficient add/remove but slow read/write 302 | 303 | ### SLList [Singly-Linked List] 304 | 305 | - Implements the **Stack** and **Queue** interfaces 306 | - **push(), pop() in O(1)** 307 | - **add(), remove() in O(1)** 308 | 309 | ![linked-list](img/LinkedList.png) 310 | 311 | ### DSList [Doubly-Linked List] 312 | 313 | - Forward and backwards pointers at each node 314 | - Implements the **List** interfaces 315 | - **get(), set() in O(1 + min(i, n-i))** 316 | - **add(), remove() in O(1 + min(i, n-i))** 317 | 318 | ![doubly-linked-list](img/DoublyLinkedList.png) 319 | 320 | ### SELList [Space-Efficient Linked List] 321 | 322 | - Like a doubly-linked list, but uses block size _b_ 323 | - Is a series of **ArrayDeque** with _next_ and _prev_ pointers 324 | - Implements the **List** interfaces 325 | - **get(), set() in O(1 + min(i, n-i)/_b_)** 326 | - **add(), remove() in O(1 + min(i, n-i)/_b_)** 327 | - is quicker because you can skip blocks of data 328 | 329 | ## Skiplist 330 | 331 | - Like a singly-linked list, with 'skips' 332 | - Randomly generated structure 333 | - Faster searches than linked lists 334 | - Additional nodes with pointers that allow 'skipping' 335 | - Successor search: **find(x) will return smallest value ≥ x** 336 | - **find(), add(), remove() in O(log n)** 337 | 338 | ![sset-interface](img/SSetInterface.png) 339 | 340 | ## List Implementations 341 | 342 | | | get/set | add/remove | 343 | |------------|---------------------|---------------------| 344 | | Arrays | _O(1)_ | _O(1 + min(i,n-i))_ | 345 | | LinkedList | _O(1 + min(i,n-i))_ | _O(1)`*`_ | 346 | | Skiplist | _O(log n)_ | _O(log n)_ | 347 | 348 | `*given a pointer to the location, else traversal is necessary` 349 | 350 | ## Definitions 351 | 352 | **Random variable:** a random sample from a group of values 353 | 354 | **Expected value:** average value of a random variable 355 | 356 | **Indicator variable:** random variable with values of 0 or 1 357 | 358 | **Linearity of Expectation:** the expected value of a sum is equal to the sum of expected values 359 | 360 | `Expected height of node [if coin flips were used]:` 361 | 362 | P(x = 1) = 1/2 // prob. that tails on first flip 363 | P(x = 2) = 1/4 // prob. that tails on second flip 364 | P(x = 3) = 1/8 // prob. that tails on third flip 365 | ... 366 | P(x = i) = 1/(2^i) 367 | 368 | Thus, 369 | E[x] = i*Sum(1/2^i) // for all natural numbers 370 | E[x] = Sum(E[I_j]) 371 | E[x] = Sum(P(I_j = i)) 372 | 373 | Indicator variable: 1 if tails, 0 is heads 374 | P(I_1 = 1) = 1 375 | P(I_2 = 1) = 1/2 376 | ... 377 | P(I_j = 1) = 1/(2^(i-1)) 378 | 379 | let S = Sum(P(x = i)) = 1 + 1/2 + 1/4 + ... 380 | 381 | therefore, 382 | S/2 = 1/2 + 1/4 + 1/8 + ... 383 | 384 | S - S/2 = 1 385 | => S = 2 386 | 387 | E[x] = Sum(P(I_j = i)) = S = 1 + 1/2 + 1/4 + ... 388 | E[x] = 2 389 | 390 | `Expected number of elements in the skiplist:` 391 | 392 | E[n_i] = ? 393 | 394 | I_(i,j) = 1 if in list, 0 is not in list 395 | // i is 0...n-1, number of nodes in list 396 | 397 | // expected value of sum of indicator(element in list) 398 | E[n_i] = E[ Sum( I_(i,j) ) ] 399 | E[n_i] = Sum( E[ I_(i,j) ] ) 400 | E[n_i] = Sum( 1/(2^i) ) // average number values in each node 401 | E[n_i] = n * ( 1/(2^i) ) // average height(node) * number of nodes 402 | 403 | `Average height of skiplist:` 404 | 405 | h = # of levels in list 406 | 407 | I_i = 1 if level is not empty, 0 if level empty 408 | 409 | // expected value of sum of indicator(level not empty) 410 | E[h] = E[ Sum( I_i ) ] // from 0...infinity [no max height] 411 | E[h] = Sum( E[ I_i ] ) 412 | 413 | I_i ≤ n_i // if level exists, less likely than number of nodes 414 | 415 | E[I_i] ≤ E[n_i] = n/(2^i) 416 | 417 | // use log(n) since we know to prove O(log n) 418 | E[h] = E[ I_i ]{ from [0] to [log(n)] } 419 | + E[ I_i ]{ from [log(n) + 1] to [infinity] } 420 | 421 | E[h] = [ log(n) + 1 ] + [ 1 ] // because math 422 | 423 | E[h] = log(n) + 2 ≤ log(n) + 3 424 | 425 | `Average length of skiplist:` 426 | 427 | R_i = # of horizontal steps at level ≤ n_i 428 | l = Sum(R_i) 429 | 430 | E[R_i] ≤ E[ # node height not promoted ] 431 | E[R_i] ≤ E[ # node height promoted ] - 1 432 | E[R_i] ≤ S - 1 // S = 2 from above 433 | E[R_i] ≤ 1 434 | 435 | let sp = total length of search path 436 | E[sp] = E[h] + E[l] 437 | E[sp] = ( log(n) + 3 ) + E[ Sum(R_i) ] 438 | E[sp] = ( log(n) + 3 ) + Sum( E[ R_i ] ) 439 | E[sp] ≤ ( log(n) + 3 ) 440 | + Sum(1){ from [0] to [log(n)] } 441 | + Sum( E[ n_i ] ){ from [log(n) + 1] to n } 442 | E[sp] ≤ ( log(n) + 3 ) 443 | + log(n) 444 | + Sum( n/(2^i) ){ from [log(n) + 1] to n } 445 | E[sp] ≤ 2*log(n) + 6 446 | 447 | E[sp] = O(log n) + O(1) 448 | 449 | ## HashTables 450 | 451 | - Unordered sets with fast access 452 | - Associative array 453 | - Index elements into a range of int 454 | - for non-integer elements, use hashCode() 455 | 456 | ![hash-table](img/HashTable.png) 457 | 458 | ### Hashing 459 | 460 | - Computing an [integer] index into the array 461 | 462 | ### ChainedHashTable 463 | 464 | - Implements the **USet** interface 465 | - **find(), add(), remove() in O(n_i)** 466 | - where *n_i* is based of size of list at index 467 | 468 | `// m ≥ 1 add() / remove() calls, results in O(m) time on resize()` 469 | 470 | ### Universal Hashing 471 | 472 | A hash function, hash(x):int -> {0,...,m-1}, is 473 | universal if, for any elements x, y: 474 | 475 | 1. if x == y, then hash(x) == hash(y) 476 | 477 | 2. if x != y, then Prob{ hash(x) == hash(y) } = 1/m 478 | 479 | - If a hash function gives probablility of 2/m, then it can be called _nearly-universal_ 480 | 481 | ### HashCodes 482 | 483 | Methods of Java Object: 484 | 485 | - .hashCode(), integer representation of object 486 | - .equals(), compare two object references 487 | 488 | Equal objects must have equal hash codes 489 | 490 | - a.equals(b) => a.hashCode() == b.hashCode() 491 | 492 | but, reverse is not true: 493 | 494 | - a.hashCode() == b.hashCode() =/> a.equals(b) 495 | - Same hashcode does not imply, same object 496 | - !a.equals(b) =/> a.hashCode() != b.hashCode() 497 | - Different object does not mean different hashcode 498 | 499 | ## Binary Trees 500 | 501 | ![binary-tree](img/BinaryTree.png) 502 | 503 | **Root:** top-most node 504 | **Internal:** nodes that have children 505 | **Leaf:** nodes with no children 506 | **External:** null nodes [children of leaf nodes] 507 | 508 | **Depth:** distance from root 509 | **Level:** set of nodes at same depth 510 | **Height:** largest depth for subtree at node 511 | **Size:** number of nodes for subtree at node [inclusive of current node] 512 | 513 | How to calculate the size of a subtree [recursively] 514 | 515 | ``` java 516 | int size(Node u) { 517 | if(u == null) return 0; // external node 518 | // add one each time, count this node 519 | return size(u.left) + size(u.right) + 1; 520 | } 521 | ``` 522 | 523 | How to calculate the height of a subtree [recursively] 524 | 525 | ``` java 526 | int height(Node u) { 527 | if(u == null) return -1; // external node, went too far 528 | // add one each time, count this node 529 | return max( height(u.left) + height(u.right) ) + 1; 530 | } 531 | ``` 532 | 533 | How to calculate the depth of a node [recursively] 534 | 535 | ``` java 536 | int depth(Node u) { 537 | if(u == null) return -1; // root node, went too far 538 | // add one each time, count this node 539 | return depth(u.parent) + 1; 540 | } 541 | ``` 542 | 543 | ### Binary Search Tree [BST] 544 | 545 | - Implements the **SSet** interface 546 | - **find(), add(), remove() in O(n)** 547 | 548 | ### Adding Node to Binary Search Tree 549 | 550 | ``` java 551 | boolean addNode(x) { 552 | last = FindLast(x); // successor search 553 | if(x == last) return false; // no duplicates 554 | if(x.value < last.value) 555 | last.right = x; 556 | else 557 | last.left = x; 558 | return true; 559 | } 560 | ``` 561 | 562 | ### Removing Node from Binary Search Tree 563 | 564 | **Case 1:** Node is a leaf [no children] 565 | 566 | - Just remove node. 567 | 568 | **Case 2:** Node has one child 569 | 570 | - Node can be replaced by child node 571 | 572 | **Case 3:** Node has two children 573 | 574 | - Replace the node with inorder successor 575 | - replace with node at lower level, favouring left side 576 | 577 | ### Random Binary Search Trees [RBST] 578 | 579 | Balanced trees are statistically more likely. 580 | 581 | - Implements the **SSet** interface 582 | - **contructed in O( n•log(n) )** 583 | - **add(), remove(), find()) in O(log n)** 584 | 585 | `// search path is at most 2•log(n) + O(1)` 586 | 587 | ### Treaps 588 | 589 | **Has an extra priority:**
590 | Parent priority should be less than child priority.
591 | This has the property of bounding the height of the tree. 592 | 593 | - Implements the **SSet** interface 594 | - Priorities are randomly applied 595 | - **contructed in O( n•log(n) )** 596 | - **find(), add(), remove() in O(log n)** 597 | 598 | ![treap](img/Treap.png) 599 | 600 | ### Scapegoat Tree 601 | 602 | BST that with height maintained within O(log n), rebuilt if too unbalanced.
603 | Limited with integer q, where height ≤ log_{3/2}(q) 604 | 605 | - Implements the **SSet** interface 606 | - Rebuild only one search path that triggered rebuild 607 | - this ensures that not entire tree is rebuilt 608 | - **rebuild() in O(log n) amortized** 609 | - **find(), add(), remove() in O(log n)** 610 | 611 | ![scapegoat](img/Scapegoat.png) 612 | 613 | `// m calls to add() / remove (), results in O( m•log(n) time spent on rebuild()` 614 | 615 | ## Binary Search Tree Implementations 616 | 617 | | | find() | add() | remove() | 618 | |------------------|------------------------|------------------------|------------------------| 619 | | BST | _O(n)_ | _O(n)_ | _O(n)_ | 620 | | RBST / Treaps | _O(log n)_ [expected] | _O(log n)_ [expected] | _O(log n)_ [expected] | 621 | | Scapegoat Trees | _O(log n)_ [amortized] | _O(log n)_ [amortized] | _O(log n)_ [amortized] | 622 | | 2-4 / RedBlack Trees | _O(log n)_ [worst-case] | _O(log n)_ [worst-case] | _O(log n)_ [worst-case] | 623 | 624 | ### Sorted Set Implementations 625 | 626 | | | Runtime | 627 | |--------------------------|-------------------------| 628 | | Skiplists | _O(log n)_ [expected] | 629 | | Treaps | _O(log n)_ [expected] | 630 | | Scapegoat Trees | _O(log n)_ [amortized] | 631 | | **2-4 / RedBlack Trees** | _O(log n)_ [worst-case] | 632 | 633 | ### 2-4 Tree 634 | 635 | Tree where every leaf has the same depth. 636 | 637 | - Implements the **SSet** interface 638 | - All leaves have equal depth 639 | - All internal nodes have 2-4 children 640 | - **find(), add(), remove() in O(log n) [worst-case]** 641 | 642 | ![24Tree](img/24Tree.png) 643 | 644 | ### RedBlack Tree 645 | 646 | A self-balancing binary search tree, built off a 2-4 Tree, where each node has a 'colour'. 647 | 648 | - Implements the **SSet** interface 649 | - Uses colour to remain balanced when adding / removing 650 | - There is the same number of black nodes on every root to leaf path 651 | - i.e. equal sum of colours on any root to leaf path 652 | - No red nodes can be adjacent 653 | - red nodes must have black parent 654 | - left-leaning: if left node is black, then right node must be black 655 | - **Maximum height of 2•log(n)** 656 | - **find(),add(), remove() in O(log n) [worst-case]** 657 | 658 | ![redblack](img/RedBlack.png) 659 | 660 | #### Adding Node to RedBlack Tree 661 | 662 | Case 0: black parent... 663 | 664 | **Case 1:** Adding red node with red parent, but black uncle 665 | 666 | - Rotate left or right at black grandparent 667 | - Parent (Red->Black) 668 | - Grandparent (Black->Red) 669 | 670 | **Case 2:** Adding red node with red parent and red uncle 671 | 672 | - make grandparent red, and parent and uncle black 673 | 674 | ![adding-red-node](img/AddingRedNode.png) 675 | 676 | ## Heaps 677 | 678 | **Heap Property:** Each node is more extreme than [or equal to] its parent. 679 | 680 | ### Binary Heaps 681 | 682 | A complete Binary Tree that also maintains the heap property. 683 | 684 | - Implements the [priority] **Queue Interface** 685 | - Allows to find / remove most extreme node with peek() / remove() 686 | - **add(), remove() in O(log n)** 687 | - **peek() in O(1)** 688 | 689 | ![binary-heap](img/BinaryHeap.png) 690 | 691 | `// m ≥ 1 add() / remove() calls, results in O(m) time on resize()` 692 | 693 | ### Eytzinger Method 694 | 695 | A method to represent a complete binary tree as an array 696 | 697 | **Parent:** can be found at (i-1)/2 698 | **Left Child:** can be found at 2i+1 699 | **Right Child:** can be found at 2i+2 700 | 701 | ### Meldable Heap 702 | 703 | A randomized heap, not bound by an shape or balancing. 704 | 705 | - Implements the [priority] **Queue Interface** 706 | - Simpler to implement, and good worst-case time efficiency 707 | - **add(), remove() in O(log n)** 708 | 709 | ### Random Walks 710 | 711 | A path through a binary tree [i.e. the expected depth of a node]. 712 | 713 | - Starting from root node 714 | - Random chance to go to left to right child 715 | - Ends at external nodes 716 | 717 | `// The expected depth of a node is ≤ log(n+1)` 718 | 719 | ## Sorting Alogrithms 720 | 721 | **In-place:** means modifying list to be sorted [as opposed to returning new sorted list].
722 | **Stable:** means the order of elements with equal values is preserved. 723 | 724 | ### Lower bound on Comparion-based Sorting 725 | 726 | For a comparion-based algorithm, the expected number of comparions is Ω(n•log(n)). 727 | 728 | ### Merge Sort 729 | 730 | Sort list by merging sorted sub-lists, reduces total number of comparisons needed. 731 | 732 | 1. Divide list into equally sized halves until 1 element per sub-list 733 | 2. Sort sub-list [recursively] 734 | 3. Merge sub-list using comparator 735 | 736 | - Comparison-based 737 | - **Not in-place** 738 | - **Stable** 739 | - **Runs in O(n•log(n)) time** 740 | 741 | `// performs at most n•log(n) comparisons` 742 | 743 | ### Heap Sort 744 | 745 | Sort by traversing down a heap tree. 746 | 747 | 1. Create a heap from list 748 | 2. Delete the root node [in list, a[n-1]] 749 | - Now root is in a[n], since n-- 750 | 3. Heapify [make sure heap property is preserved] 751 | 4. Repeat steps 2-4 until no more elements to sort 752 | 753 | - Comparison-based 754 | - **In-place** 755 | - **Not stable** 756 | - **Runs in O(n•log(n)) time** 757 | 758 | `// performs at most 2n•log(n) + O(n) comparisons` 759 | 760 | ### Quick Sort 761 | 762 | Sort using a randomly selected value as pivot point, then sorting the sub-lists.
763 | Since random selection, might choose worst value [ideally middle value]. 764 | 765 | 1. Randomly select value 766 | 2. Add all values less than to left sub-list, otherwise add to right sub-list 767 | 3. Repeat until 1 element in sub-list 768 | 769 | - Comparison-based 770 | - **In-place** 771 | - **Not stable** 772 | - **Runs in O(n•log(n)) [expected] time** 773 | 774 | `// performs at most 2n•log(n) + O(n)` 775 | 776 | ### Comparison-based Algorithms 777 | 778 | | | Comparisons | In-place | Stable | 779 | |------------|------------------------------------|----------|--------| 780 | | Merge Sort | _n•log(n)_ [worst-case] | no | yes | 781 | | Heap Sort | _1.38n•log(n) + O(n)_ [worst-case] | yes | no | 782 | | Quick Sort | _2n•log(n) + O(n)_ [expected] | yes | no | 783 | 784 | **Merge Sort:** 785 | 786 | - Fewest comparisons 787 | - Does not rely on randomization [guaranteed runtime] 788 | - Not in-place [expensive memory usage] 789 | - Stable 790 | - Much better at sorting a linked list 791 | - no additional memory is needed with pointer manipulation 792 | 793 | **Quick Sort:** 794 | 795 | - Second fewest comparisons 796 | - Randomized [expected runtime] 797 | - In-place [memory efficient] 798 | - Not stable 799 | 800 | **Heap Sort:** 801 | 802 | - Most comparisons 803 | - Not randomized [guaranteed runtime] 804 | - In-place [memory efficient] 805 | - Not stable 806 | 807 | ### Counting Sort 808 | 809 | Counting array is used to keep track of duplicates; it is then used to construct the sorted list. 810 | 811 | - Not comparison-based 812 | - **Not in-place** 813 | - **Not stable** 814 | - **Runs in O(n+k) time** 815 | - n integers 816 | - range of 0...k 817 | 818 | `// efficient for integers when the length is roughly equal to maximum value k-1` 819 | 820 | ### Radix Sort 821 | 822 | Sorts w-bit integer with counting sort on d-bits per integer [least to most significant] 823 | 824 | - Not comparison-based 825 | - **Not in-place** 826 | - **Not stable** 827 | - **Runs in O(c•n) time** 828 | - n w-bit integers 829 | - range of 0...(n^c - 1) 830 | 831 | ## Graphs 832 | 833 | A graph is a pair of sets: G(V,E) 834 | 835 | - **V** is the set of all vertices 836 | - **E** is the set of all edges 837 | 838 | ![graph](img/graph.png) 839 | 840 | ### Graph Interface 841 | 842 | Interface that defines characteristics of a graph 843 | 844 | - **addEdge(i,j):** adds an edge between nodes i and j 845 | - **emoveEdge(i,j):** removes edge between nodes i and j 846 | - **hasEdge(i,j):** returns true if edge exists between nodes i and j 847 | - **outEdges(i):** returns set of all outbound edges from node i 848 | - **inEdges(i):** returns set of all inbound edges from node i 849 | 850 | | | Adjacency Matrix | Adjacency List | 851 | |------------|---------------------|---------------------| 852 | | addEdge | _O(1)_ | _O(1)_ | 853 | | removeEdge | _O(1)_ | _O(deg(i))_ | 854 | | hasEdge | _O(1)_ | _O(deg(i))_ | 855 | | outEdge | _O(n)_ | _O(1)_ | 856 | | inEdge | _O(n)_ | _O(n+m)_ | 857 | | | | | 858 | | space used | _O(n^2)_ | _O(n+m)_ | 859 | 860 | `• n is the number of nodes`
861 | `• m is the number of edges` 862 | 863 | ### Adjacency Matrix 864 | 865 | An _n x n_ matrix representing adjacent nodes. 866 | 867 | - useful for dense graphs [approx. n^2 edges] 868 | - memory usage is acceptable 869 | - Matrix algebraic operations to computer property of graph 870 | - like finding shortest paths between all pairs of vertices 871 | 872 | ### Adjacency List 873 | 874 | Stores all outbound edges from a node. 875 | 876 | - Is better to use than **Adjacency Matrix** if memory restricted, or for outEdges() 877 | 878 | e.g. 879 | 880 | | Source Node (n) | Adjacent Nodes (m) | 881 | |-----------------|--------------------| 882 | | 0 | 2,4,5,6 | 883 | | 1 | 2,3 | 884 | | 2 | 5 | 885 | | 3 | 0,6,3 | 886 | | 4 | 1,2,3,5,6 | 887 | | 5 | 0,6 | 888 | | 6 | 4,6 | 889 | 890 | ### Graph Traversal 891 | 892 | We can use Breadth-first or Depth-first search order to visit every node. 893 | 894 | **Preorder:** Start at the root node, go left always, else go right
895 | [visits each node **before its children**] 896 | 897 | - Used to copy the tree 898 | 899 | **Inorder:** All nodes from left to right [visually]
900 | [visits each node **after its left** children] 901 | 902 | - Useful for getting size of all subtrees 903 | 904 | **Postorder:** Bottom to top, with left priority
905 | [visits node **after its children**] 906 | 907 | - Used to delete tree 908 | 909 | #### Breadth-first Search 910 | 911 | Go through all adjacent nodes first the. 912 | 913 | - Good for finding quickest paths from one node to another [but not unique paths]. 914 | - There could be equally quick paths not found 915 | 916 | **Process:** 917 | 918 | - You do this with a queue and list 919 | - queue stores position we are at 920 | - add all unseen adjacent nodes to queue and seen list 921 | - remove value from queue 922 | - go to removed value, repeat 923 | - list stores nodes we have seen 924 | - so that seen values are not added to queue 925 | 926 | #### Depth-first Search 927 | 928 | Go through list based of a priority. 929 | 930 | - Good for finding node with highest / lowest priority? 931 | 932 | **Process:** 933 | 934 | - You do this with a stack and list 935 | - stack stores position we are at 936 | - add current node to seen list 937 | - add smallest unseen adjacent nodes stack [recursively] 938 | - list stores nodes we have seen 939 | - so that recursive calls are always to smallest unseen node 940 | 941 | ### Adjacency Matrix vs. Adjacency List 942 | 943 | It is better to use **Adjacency List** for **traversals**. 944 | 945 | | | Adjacency Matrix | Adjacency List | 946 | |------------|---------------------|---------------------| 947 | | Breadth | _O(n^2)_ | _O(n+m)_ | 948 | | Depth | _O(n^2)_ | _O(n+m)_ | 949 | -------------------------------------------------------------------------------- /Final Review.md: -------------------------------------------------------------------------------- 1 | # Final Review Questions 2 | 3 | ## 1: JCF & Big-Oh 4 | 5 | ### 1.1 Big-Oh Notation 6 | 7 | 1. What is O(n)? What kind of object is it? 8 | 9 | It is a set of all functions.. 10 | 11 | O(f(n)) denotes the set of functions g(n) where c•f(n) starts to dominate at large enough n. 12 | 13 | It describes the limiting behaviour of a function. In terms of algorithms, it describes the worst case runtime. It is a set of all functions that are larger than the runtime of an algorithm, at sufficiently large n. 14 | 15 | It describes the growth rate of an algorithm's runtime as the number of elements increases. 16 | 17 | 2. What does the statement 2n + 3 = O(n^2) mean? 18 | 19 | It means that the function 2n+3 is a member of the Set O(n^2) 20 | 21 | It means that for a given value k, 2n + 3 ≤ k•n^2 22 | 23 | 3. Recall the basic big-O hierarchy: for any constants a,b > 1: 24 | 25 | O(a) < O(log n) < O(n) < O(n•log n) < O(n^b) < O(c^n) 26 | 27 | Where do the functions 2n^2 = O(n^b), 100nlogn = O(n•log n), and log(n^3) = O(n•log n) fit into this hierarchy? 28 | 29 | 4. What is the running time (in big-o notation) for the following function, assuming the method foo() runs in constant time? 30 | 31 | ``` java 32 | for(int i=1; iO(n) 33 | for(int j=n-i; j O(n) 34 | foo(); // O(1) 35 | ``` 36 | 37 | Thus, this function has a runtime that is O(n^2). 38 | 39 | ### 1.2 Java Collections Framework - Interfaces 40 | 41 | All of these questions should be considered in the context of the interfaces in the JCF. 42 | 43 | 1. Explain the differences and similarities between a Set and a List. 44 | 45 | - A Set has no duplicates, whereas a List may have duplicates. 46 | - A List has an order to its elements, wheras a set is unordered. 47 | - List elements can be accessed with an index [quick get] 48 | - Set elements can be added / removed easily 49 | - Both contain elements. 50 | - Sorted Sets have successor search 51 | 52 | 2. Explain the difference between a Collection and a Map. Could it also make sense to have Map be a subclass of Collection? 53 | 54 | A Collection contains values but no key 55 | 56 | - Ordered or Unorded 57 | 58 | A Map organizes values based of a key [key-value pairs] 59 | 60 | - It is possible to find a value knowing only a key 61 | - No duplicate entries 62 | - Unordered 63 | 64 | 3. Which of the JCF interfaces would be the most useful if we want to store a collection of students enrolled in COMP2402 so that we can quickly check if a student is enrolled in COMP2402? 65 | 66 | USet: if we are only storing name or student number [or both together as one value] 67 | HashTable: has quick contains() if we are storing name and student number seperately 68 | 69 | 4. How does your answer to the previous question change if we also want to store some auxiliary information (e.g., a mark) with each student. 70 | 71 | HashTable: unordered Map, quick for contains() 72 | 73 | 5. A Bag is like a set except that elements can be stored more than once. Explain how you could implement a Bag using a Map. 74 | 75 | You can implement Bag interface by using key as the identifier for the element, and value as a counter for how many instances of this element are in the bag. 76 | 77 | ### 1.3 Java Collections Framework - Implementations 78 | 79 | 1. Explain why it is important that elements that are stored in a Set or Map aren't modified in a way that affects the outcome of the equals() method. 80 | 81 | This is important because, otherwise they cannot be sorted using a comparator, since this uses the equals() method of the object. 82 | 83 | 2. Describe the running time of the methods get(i) and set(i,x) for an ArrayList versus a LinkedList. 84 | 85 | ArrayList is quicker since no need to traverse. 86 | - O(1) 87 | 88 | LinkedList traversal is minimized if doubly linked list 89 | - O(min(n-i, i) + 1) 90 | 91 | 3. Describe the running time of the method add(i,x) for an ArrayList versus a LinkedList. 92 | 93 | ArrayList is good for adding or removing at the front / back because no need to shift elements. 94 | - ArrayStack: O(n-i+1) 95 | - ArrayDeque: O(min(n-i,i) + 1) 96 | LinkedList is good for adding anywhere, as long as there is a pointer to the location being added to, otherwise traversal through each element is needed. 97 | - O(1) [given pointer to location] 98 | 99 | 4. For each of the following methods, decide if it is fast or slow when: 100 | 101 | **(a)** when l is an ArrayList
102 | **(b)** when l is a LinkedList. 103 | 104 | ``` java 105 | // Good for ArrayList 106 | // Good for LinkedList 107 | public static void frontGets(List l, int n) { 108 | for (int i = 0; i < n; i++) { 109 | l.get(0); 110 | } 111 | } 112 | // Good for ArrayList 113 | // Good for LinkedList 114 | public static void backGets(List l, int n) { 115 | for (int i = 0; i < n; i++) { 116 | l.get(l.size()-1); 117 | } 118 | } 119 | // Good for ArrayList 120 | // Bad for LinkedList 121 | public static void randomGets(List l, int n) { Random gen = new Random(); 122 | for (int i = 0; i < n; i++) { 123 | l.get(gen.nextInt(l.size())); 124 | } 125 | } 126 | // Good for ArrayList 127 | // Good for LinkedList 128 | public static void insertAtBack(List l, int n) { 129 | for (int i = 0; i < n; i++) { 130 | l.add(new Integer(i)); 131 | } 132 | } 133 | // Bad for ArrayList, unless ArrayDeque 134 | // Good for LinkedList 135 | public static void insertAtFront(List l, int n) { 136 | for (int i = 0; i < n; i++) { 137 | l.add(0, new Integer(i)); 138 | } 139 | } 140 | // Bad for ArrayList, Unless DualArrayDeque 141 | // Good for LinkedList 142 | public static void insertInMiddle(List l, int n) { 143 | for (int i = 0; i < n; i++) { 144 | l.add(new Integer(i)); 145 | } 146 | for (int i = 0; i < n; i++) { 147 | l.add(n/2+i, new Integer(i)); 148 | } 149 | } 150 | ``` 151 | 152 | ## 2: Lists as Arrays 153 | 154 | These questions are all about implementing the List interface using arrays. 155 | 156 | ### 2.1 ArrayStacks 157 | 158 | Recall that an ArrayStack stores n elements in a backing array a at locatiosn a[0],...,a[n-1]: 159 | 160 | ``` java 161 | public class ArrayStack extends AbstractList { 162 | T[] a; 163 | int n; 164 | ... 165 | } 166 | ``` 167 | 168 | 1. Describe the implementation and running times of the operations get(i) and set(i,x) in an ArrayStack. 169 | 170 | An ArrayStack is just an array with access only to back. Superceded by an ArrayDeque. 171 | 172 | - get(), set() in O(1) 173 | 174 | 2. Recall that the length of the backing array a in an ArrayStack doubles when we try to add an element and n + 1 > a.length. Explain, in general terms why we choose to double rather than just add 1 or a constant. 175 | 176 | Better to double size of the backing array because otherwise we would have to resize after each element that is added. A constant isn't used because if you have a small list you don't want 100 unused spaces, but when working with large sets with highly variable size you don't want to be resizing every 100 if you are adding or removing 1000 each second. 177 | 178 | A dynamic number that is relative to the size of the stack is best. 179 | 180 | 3. Recall that, immediately after an ArrayStack is resized it has a.length = 2*n. 181 | 182 | **a.** If we are currently about to grow the backing array a, what can you say about the number of add() and remove() operations since the last time the ArrayStack was resized? 183 | 184 | At least n/2 add or remove operations. 185 | 186 | - If we have n items: 187 | - Growing: last time it was resized it had n/2 items before [n/2 calls] 188 | 189 | **b.** Recall that we shrink the back array a when 3*n < a.length. If we are currently about to shrink the backing array a, what can you say about the number of add() and remove() operations since the last time the ArrayStack was resized? 190 | 191 | We had 3n items before 192 | - so at least 2n calls 193 | 194 | 4. From the previous question, what can you conclude about the total number of elements copied by resize() if we start with an empty ArrayStack and perform m add() and remove() operations? 195 | 196 | At most 2m items will be copied for ArrayStack/ArrayQueue/ArrayDeque after m calls. 197 | 198 | 5. What is the amortized (or average) running time of the add(i,x) and remove(i) operations, as a function of i and size(). 199 | 200 | add / remove: O(n-i+1) + 1 201 | - Quick to add to back 202 | 203 | get / set: O(1) 204 | 205 | 6. Why is the name ArrayStack a suitable name for this data structure? 206 | 207 | It is suitable because it implements the Stack Interface, FILO, and is implemented using arrays. 208 | 209 | ### 2.2 ArrayDeques 210 | 211 | Recall that an ArrayDeque stores n elements at locations a[j], a[(j+1)%a.length], ..., a[(j+n-1)%a.length]: 212 | 213 | ``` java 214 | public class ArrayDeque extends AbstractQueue { 215 | T[] a; 216 | int j; 217 | int n; 218 | ... 219 | } 220 | ``` 221 | 222 | 1. Describe, in words, how to perform an add(i,x) operation 223 | **(a)** if i < n/2 224 | **(b)** if i ≥ n/2. 225 | 226 | ArrayDeque appears like a circular array, no need to worry about the actual front or back of the array. 227 | 228 | - If the index is less than n/2, then shift values left since fewer values to shift. 229 | - Else, shift values right 230 | 231 | - There is a private index j which stores where the first value is: 232 | - i < n/2, j-- 233 | - i ≥ n/2, j = j 234 | 235 | 2. What is the running time of add(i,x) and remove(i) operations as a function of i and size()? 236 | 237 | ArrayDeque is faster than ArrayStack because it has front access 238 | - O(min(n-i,i) + 1) 239 | 240 | 3. Describe, in words, why using System.arraycopy() to perform shifting of elements in the add(i,x) and remove(i) operations is so much more complicated for an ArrayDeque than an ArrayStack. 241 | 242 | Because the first index in the backing array does not necessarily correspond to the first index of the ArrayDeque. 243 | 244 | 4. Explain why, using an example, if a.length is a power of 2, then x % a.length = x & (a.length-1). Why is this relevant when discussing ArrayDeques? 245 | 246 | This is relavant because you can check if the front of the ArrayDeque is pointing to the last index in the backing array, so it can be reset to the 0th index if an element is added. 247 | 248 | ### 2.3 DualArrayDeques 249 | 250 | Recall that a DualArrayDeque implements the List interface using two ArrayStacks: 251 | 252 | ``` java 253 | public class DualArrayDeque extends AbstractList { 254 | ArrayStack front; 255 | ArrayStack back; 256 | ... 257 | } 258 | ``` 259 | 260 | 1. If the elements of the list are x(0, ... x_(n-1), describe how these are distributed among front and back and in what order they appear. 261 | 262 | 2. Recall that we rebalance the elements among front and back when 3•front.size() < back.size() or vice versa. After we rebalance, we have front.size() == back.size() ± 1. What does this tell us about the number of add() and remove() operations between two consecutive rebalancing operations? 263 | 264 | This means that we had at least n/2 calls to add() / remove(). 265 | 266 | - assume initially balanced arrays 267 | - each array has n/2 268 | - before rebalancing, front array had n/4, and back array has 3n/4 269 | - difference of n/2 270 | - this means that there was n/2 add() / remove(), (where n is the final size) 271 | 272 | ### 2.4 RootishArrayStacks 273 | 274 | Recall that a RootishArrayStack stores a list in a sequence of arrays (blocks) of sizes 1, 2, 3, 4, ... 275 | 276 | ``` java 277 | public class RootishArrayStack extends AbstractList { 278 | List blocks; 279 | int n; 280 | ... 281 | } 282 | ``` 283 | 284 | 1. If a RootishArrayStack has r blocks, then how many elements can it store? 285 | 286 | Each block stores r elements, so r+(r-1)+(r-2)..1 elements 287 | 288 | Geometric Series: r(r+1) / 2 289 | 290 | 2. Explain how this leads to the equation: 291 | 292 | b(b+1)/2 < i+1 < (b+1)(b+2)/2 293 | 294 | - The number of indices less than or equal to i are i+1 [inclusive of element i] 295 | - The block at which i is contained must be at least b(b+1)/2 296 | - But cannot be within the next block given by b+1(b+2)/2 297 | 298 | 3. In a RootishArrayStack that contains n elements, what is the maximum amount of space used that is not dedicated to storing data? 299 | 300 | The amount of wasted space in a RootishArrayStack is sqrt(n) 301 | - Makes it memory-efficient 302 | 303 | ## 3: Linked Lists 304 | 305 | ### 3.1 Singly-Linked Lists 306 | 307 | Recall our implementation of a singly-linked list (SLList): 308 | 309 | ``` java 310 | protected class Node{ 311 | T x; 312 | Node next; 313 | } 314 | public class SLList extends AbstractQueue { 315 | Node head; 316 | Node tail; 317 | int n; 318 | ... 319 | } 320 | ``` 321 | 322 | 1. Draw a picture of an SLList containing the values a, b, c, and d. Be sure to show the head and tail pointers. 323 | 324 | ...in markdown? [nah] 325 | 326 | 2. Consider how to implement a Queue as an SLList. When we enqueue (add(x)) an element, where does it go? When we dequeue (remove()) an element, where does it come from? 327 | 328 | A queue can be created with two pointers: head and tail 329 | 330 | - The tail should be here new nodes are added to, so they can point to the existing queue 331 | - Removals should be made at the head, so that head.next becomes the new head 332 | 333 | 3. Consider how to implement a Stack as an SLList. When we push an element where does it go? When we pop an element where does it come from? 334 | 335 | Only one pointer is needed: head 336 | 337 | - Insertion and removals should be done at the head 338 | 339 | 4. How quickly can we find the ith node in an SLList? 340 | 341 | Quick to find if near the front [head] 342 | - O(1+i) 343 | 344 | 5. Explain why we can't have an efficient implementation of a Deque using an SLList. 345 | 346 | You don't have quick access to the predecessor to the tail 347 | 348 | - Tail is only good for insertion 349 | - Can be fixed with doubly linked list 350 | 351 | ### 3.2 Doubly-Linked Lists 352 | 353 | Recall our implementation of a doubly-linked list (DLList): 354 | 355 | ``` java 356 | protected class Node { 357 | Node next, prev; 358 | T x; 359 | } 360 | public class DLList extends AbstractSequentialList { 361 | protected Node dummy; 362 | protected int n; 363 | ... 364 | } 365 | ``` 366 | 367 | 1. Explain the role of the dummy node. In particular, what are dummy.next and dummy.prev? 368 | 369 | The dummy node stores the pointers to the front and back nodes 370 | - dummy.next is the head 371 | - dummy.prev is the tail 372 | 373 | 2. One of the following two functions correctly adds a node u before the node p in the DLList, the other one is incorrect. Which one is correct? 374 | 375 | ``` java 376 | // correct implementation 377 | protected Node add(Node u, Node p){ 378 | u.next = p; 379 | u.prev = p.prev; 380 | u.next.prev = u; 381 | u.prev.next = u; 382 | n++; 383 | return u; 384 | } 385 | // incorrect implementation 386 | protected Node add(Node u, Node p){ 387 | u.next = p; 388 | u.next.prev = u; // this overwrites p.prev 389 | u.prev = p.prev; 390 | u.prev.next = u; 391 | n++; 392 | return u; 393 | } 394 | ``` 395 | 396 | 3. What is the running-time of add(i,x) and remove(i) in a DLList? 397 | 398 | Quick if no traversal is needed O(1) given a pointer. 399 | 400 | - O(min(n-i) + 1) [minimized traversal] 401 | 402 | ### 3.3 Space-Efficient Doubly-Linked-Lists 403 | 404 | Recall that a space efficient doubly-linked list implements the List interface by storing a sequence of blocks (arrays) each containing b ± 1 elements. 405 | 406 | The wasted space is divided by b, but adds b blocks 407 | 408 | - n + O(n/b + b) 409 | 410 | 1. What is the running-time of get(i) and set(i) in a space-efficient doubly-linked list? 411 | 412 | Traversals are reduced by b blocks 413 | - O(min(n-i,i)/b + 1) 414 | 415 | 2. What is the amortized running time of the add(i) operation in a space-efficient doubly-linked list? 416 | 417 | Same as regular SLL, but divided by b blocks 418 | - O(min(n-i)/b + 1) 419 | 420 | 3. In a space-efficient doubly-linked list containing n elements, what is the maximum amount of space that is not devoted to storing data? 421 | 422 | Wasted space: n pointers + O(n/b + b) 423 | 424 | ## 4: SkipLists 425 | 426 | Recall that a skiplist stores elements in a sequence of smaller and smaller lists L0, ..., Lk. Li is obtained from Li-1 by tossing a coin for each element in Li-1 and including the element in Li if that coin comes up heads. 427 | 428 | 1. Draw an example of a skiplist select a few elements and show the search paths for these elements 429 | 430 | Like a regualar SLL with extra randomized nodes for skipping forward 431 | 432 | 2. Explain how the reverse search path is related to the following experiment: Toss a coin repeatedly until the first time the coin comes up heads. 433 | 434 | The expected search path can be described as the expected coin flip, since each additional height in a node due to a probability. 435 | 436 | 3. If there are n elements in L0, what is the expected number of elements in L1? What about in Li? 437 | 438 | L1 = L0/2 = n/2 because there is a P(height++) = 0.5 439 | - L0 contains all node levels with 0 skips to next node [also known as all elements] 440 | 441 | Li = i/2 442 | 443 | 4. If there are n elements in L0, give an upper bound on the expected length of the search path for any particular element. 444 | 445 | O(log n) 446 | - specifically 2•log(n) + O(1) 447 | 448 | 5. Explain, briefly, how a skiplist can be used to implement the SortedSet interface. What are the running times of operations add(x), remove(x), and contains(x)? 449 | 450 | Define the length of a skip [edge]. 451 | 452 | Contains: 453 | - Go right if the next node is less than value 454 | - Go down if next node is greater than 455 | - This is a successor search 456 | 457 | add(), remove(), contains() runs in O(log n) 458 | 459 | 6. Explain, briefly, how a skiplist can be used to implement the List interface. What are the running times of the operations add(i,x), remove(i), get(i,x), and set(i,x). 460 | 461 | add(), remove(), get(), set() runs in O(log n) [expected] 462 | 463 | ## 5: Hash tables 464 | 465 | 1. If we place n distinct elements into a hash table of size m using a good hash function, how many elements do we expected to find in each table position? 466 | 467 | 2. Recall the multiplicative hash function hash(x) = (x.hashCode() * z) >>> w-d. 468 | 469 | a. In 32-bit Java, what is the value of w? 470 | - 32 bits... 471 | 472 | b. How large is the table that is used with this hash function? (In other words, what is the range of this hash function?) 473 | - The range is m - 1, where m = 2^d 474 | - 0...(2^d -1) 475 | 476 | c. Write this function in more standard mathematical notation using the mod and div (integer division) operators. 477 | hash(x) = (z•x) mod 2^w ) div 2^(w-d) 478 | 479 | 3. Explain the relationship between a class's hashCode() method and its equals(o) method. 480 | 481 | Two objects with equal values will return the same hash codes 482 | - a.equals(b) => a.hashCode() == b.hasCode() 483 | 484 | 4. Explain, in words, what is wrong with the following hashCode() method: 485 | 486 | ``` java 487 | public class Point2D{ 488 | Double x,y; 489 | ... 490 | public int hashCode(){ 491 | return x.hashCode() ^ y.hashCode(); 492 | } 493 | } 494 | ``` 495 | 496 | Give an example of many points that all have the same hashCode(). 497 | 498 | - If '^' is exponent The point 1,2 will return the same hash code as 2,1, and any two point with the same values will return the same hash codes even though they are not the same points 499 | 500 | - If '^' is XOR, then it will return 0 if x == y 501 | 502 | 5. Explain, in words, what is wrong with the following hashCode() method: 503 | 504 | ``` java 505 | public class Point2D{ 506 | Double x,y; 507 | ... 508 | public int hashCode(){ 509 | return x.hashCode() + y.hashCode(); 510 | } 511 | } 512 | ``` 513 | 514 | Give an example of 2 different points that have the same hashCode(). 515 | 516 | - This will give an issue with points of swapped values, e.g. 1,2 and 2,1 517 | 518 | ## 6: Binary Trees 519 | 520 | ### 6.1 Binary Trees 521 | 522 | 1. Draw a good sized binary tree. 523 | 524 | ...ha 525 | 526 | 2. Label the nodes of your drawing with their depth. 527 | 528 | ... 529 | 530 | 3. Label the nodes by the order they are processed in a preorder traversal. 531 | 532 | **Preorder:** Root, then left always, and then right 533 | **Inorder:** Left to right 534 | **Postorder:** Bottom to top, with left priority 535 | 536 | 4. Label the nodes by the order they are processed in an inorder traversal. 537 | 538 | ... 539 | 540 | 5. Label the nodes by the order they are processed in a postorder traversal. 541 | 542 | ... 543 | 544 | 6. Label the nodes of your tree with the sizes of their subtrees 545 | 546 | ... 547 | 548 | 7. What kind of traversal would you do to compute the sizes of all subtrees in a tree? 549 | 550 | You would use inorder traversal 551 | - Preorder is good for copying the tree [root first] 552 | - Postorder is good for deleting the tree 553 | 554 | ### 6.2 Binary Search Trees 555 | 556 | 1. Consider an array containing the integers 0...15 in sorted order. Illustrate the operation of binary search on a few (a) integer values and a few (b) non-integer values. 557 | 558 | - Check if current value is equal to expected value 559 | - if current value is smaller: go to left child, else right child 560 | 561 | 2. Draw a binary search tree containing (at least) 0...15 562 | 563 | ... 564 | 565 | 3. Show the search path for a value x in the tree and a value x' not in the tree 566 | 567 | ... 568 | 569 | 4. Insert some value x' into the tree 570 | 571 | Like finding but simply add at point search would fail. 572 | 573 | 5. Delete some value x from your tree (try this for external nodes, internal nodes with 1 child, and internal nodes with two children). 574 | 575 | **External node:** 576 | 577 | Easy, delete node... 578 | 579 | **Internal node:** 580 | 581 | One child: move child up one, done... 582 | 583 | Two children: Find closest value greater than deleted node value. Replace deleted node with this one. 584 | 585 | ## 7: Treaps 586 | 587 | 1. Choose a permutation of the values 0...15. Draw the binary search tree that results from inserting the elements of your permutation in order. Are there other permutations that could have given the same search tree? 588 | 589 | ... 590 | 591 | And yes, there are many [probablistically] 592 | 593 | 2. Explain the relationship between quicksort and random binary search trees. 594 | 595 | By building a RBST with the pivot value at the node, quick sort is implemented, since every value is compared to this pivot. 596 | 597 | Given quicksort input of size n, the recursion tree is a RBST. 598 | 599 | 3. Define the heap property for how priorities are used to make a binary tree into a Treap. 600 | 601 | The heap property states that a child's key will be more extreme than it's parent's key. This is used to organize a binary tree into a heap by adding a 'priority' key to each node. This is done to bound the height of the tree, as the keys are randomly generated. 602 | 603 | 4. Pick some random numbers p_0...p_15, and draw the treap that contains 0...15 where p_i gives the priority for number i. 604 | 605 | ... 606 | 607 | 5. Explain the relationship between random binary search trees and Treaps. 608 | 609 | Since the keys are unique and randomly generated, a Treap can be thought of as following both the heap property and binary search tree properties. 610 | 611 | Or, a Treap can be thought of as a RBST with nodes insterted by increasing priority. 612 | 613 | 6. Explain the relationship between insertion and deletion in a Treap. 614 | 615 | When values are added or removed, the tree may have to move nodes around to maintain heap property [heapify]. 616 | 617 | ## 8: Scapegoat Trees 618 | 619 | Recall that a scapegoat node is where 3•size(u) > 2•size(u.parent). 620 | 621 | They have a deterministic height [this is what triggers rebuild, when height is exceeded] 622 | 623 | 1. In a scapegoat tree, is size(u) < size(u.parent) for every non-root node u? 624 | 625 | Yes, since any subtree of u, must be a subtree of the parent node. 626 | 627 | 2. Draw an example of a tree that looks surprisingly unbalanced but is still a valid scapegoat tree. 628 | 629 | ... 630 | 631 | - Assume a value for limiting parameter q (q = n = 10) 632 | - Then the height can be up to log_{3/2}(q) 633 | - log_{3/2}(10) is about 5.6, so can draw tree with up to 5 height 634 | 635 | 3. Explain why, in a scapegoat tree, we keep two separate counters n and q that both -sort of- keep track of the number of nodes? 636 | 637 | n is the number of elements in the list 638 | 639 | q is a counter, used to maintain the upper-bound on the number of nodes 640 | 641 | They are used to bound the height, by checking if by adding / removing a node does not maintain a height ≤ log_{3/2}(q). 642 | 643 | q is initially the value of n, and incremented with each added node, and decremented with each removed node. 644 | 645 | 4. If v is a scapegoat node (for example, because 3•size(v.left) > 2•size(v)) then explain how many operations (insertion/deletions) have affected v's subtree since the last time the subtree containing v was rebuilt. 646 | 647 | at least 1/3•size(v) calls to add() / remove(). 648 | 649 | ## 9: 2-4 and Red-Black Trees 650 | 651 | Advantages of 2-4: log n height **always**; deterministic. Treap have randomness. Scapegoat has amortized cost. 652 | 653 | 1. Draw an interesting example of a 2-4 tree. 654 | 655 | - Tree with all every leaf at equal depth, all internal nodes have 2-4 children 656 | 657 | 2. Explain what happens in a 2-4 tree when an insertion causes a node to have more than 4 children. 658 | 659 | If this causes an internal node to have more than 4 children, then we split the node into two with 2 and 3 children. If the parent node now has too many children, then it too will be split. 660 | 661 | 3. Explain what happens in a 2-4 tree when a deletion causes a node to have only one child. 662 | 663 | The node is added to the sibling of the internal node, since it is guaranteed to have at least one sibling. If this causes the parent of the internal node to have less than 2 children, then it's merged with its sibling; if the parent is the root, then the sole child of the root becomes the new root. 664 | 665 | 4. Draw a red-black tree that corresponds to your 2-4 tree. 666 | 667 | Same thing, except all paths to external nodes have same number of black nodes [analagous to same depth of external nodes in 2-4 tree]. 668 | 669 | - Anywhere there are more than 2 children to a node, split into groups of one or two with red node parents. 670 | 671 | 5. Explain the relationship between the red-black tree properties and the 2-4 tree properties. 672 | 673 | A RedBlack tree simulates a 2-4 tree with a binary tree implementation. 674 | 675 | ## 10: Heaps 676 | 677 | ### 10.1 Binary Heaps 678 | 679 | These questions are about complete binary heaps represented using the Eytzinger Method. 680 | 681 | 1. Draw an example of a complete binary heap with key values. 682 | 683 | ... 684 | 685 | Binary tree that maintains the heap property, like a Treap without the priority key, implemented with an array. 686 | 687 | e.g. root is always minimum value 688 | 689 | 2. Illustrate how your example's values map into an array using the Eytzinger Method. 690 | 691 | ... 692 | 693 | Go through tree with breadth-first traversal, with left child priority. 694 | 695 | - Parent of node at index i are found at (i-1)/2 696 | - Left child of node at index i are found at 2i + 1 697 | - Right child of node at index i are found at 2i + 2 698 | 699 | 3. Consider a binary heap represented using the Eytzinger Method. Give the formulas for the parent, left child, and right child of the value stored at position i. 700 | 701 | - Parent of node at index i are found at (i-1)/2 702 | - Left child of node at index i are found at 2i + 1 703 | - Right child of node at index i are found at 2i + 2 704 | 705 | 4. When we perform a DeleteMin (remove()) operation on a heap, where do we get the value to replace the root, and what do we do with it? 706 | 707 | The easiest way is to replace the root with the last value in the array a[n-1]. 708 | 709 | - This is probably not the minimum value, thus it must be moved down [heapify] 710 | - compare value to its children 711 | - if it is larger than either one, it is swapped with the smallest child 712 | - repeat 713 | 714 | 5. Explain or illustrate the insertion algorithm for a heap 715 | 716 | - First check the size of the array, if it is full resize() 717 | - Next place new value in a[n] [first empty space in array] 718 | - Heapify 719 | - swap new value with its parent if it is smaller than the parent 720 | 721 | 6. Explain the operation of HeapSort 722 | 723 | Heap Sort: Turn everything into Binary Heap, and remove root value everytime. 724 | 725 | Remove root node [this will store it on array at a[n] after deletion] 726 | - Afterwards array will have sorted list 727 | 728 | ### 10.2 Randomized Meldable Heaps 729 | 730 | Binary Heaps with no limit to size and shape. 731 | 732 | 1. Draw two examples of heaps (not necessarily complete) and show how to meld (merge) them. 733 | 734 | ... 735 | 736 | Given two binary trees x, y: 737 | - Random coin flip if y is merged with x.left or x.right 738 | - This is done recursively 739 | 740 | 2. Explain how the add(x), and remove() operations can be done using the meld() operation. 741 | 742 | Merging only one node is the same as adding one node. 743 | 744 | To remove a node, merge its children 745 | 746 | ### 11: Sorting Algorithms 747 | 748 | 1. Explain the relative advantages of MergeSort, HeapSort, and Quicksort. Things to keep in mind are (a) the number of comparisons performed, (b) the amount of extra memory required by the algorithms, and (c) whether their running time is guaranteed or only probabilistic. 749 | 750 | Stable: Means order of equal values is preserved 751 | In-place: Means that original list is modified by sort 752 | 753 | **Merge Sort:** 754 | - Only one that is stable 755 | - Only one that isn't in-place 756 | - thus extra memory is needed 757 | - The most comparisons 758 | - No randomness, this runtime is guaranteed 759 | 760 | **Heap Sort:** 761 | - Not stable 762 | - In-place 763 | - Quickest in terms of least comparisons 764 | - No randomness, thus runtime is guaranteed 765 | 766 | **Quick Sort:** 767 | - Not stable 768 | - In-place 769 | - The second best in terms of comparisons 770 | - Randomness, thus runtime is probabilistic 771 | 772 | 2. Create a random permutation of numbers 0...15. Walkthrough the sorting of this permutation using the HeapSort, MergeSort, QuickSort, and CountingSort algorithms. 773 | 774 | ... 775 | 776 | 3. Explain how the Radix sort algorithm works. What key feature of the counting sort algorithm makes it work correctly? 777 | 778 | **Radix sort:** Best when you have a sparse array, or large range with many zeros. 779 | 780 | It uses counting sorts in sections of size _d_; Sort least significant bits first using Counting Sort, so that next significant bit duplicates are already sorted... 781 | 782 | ## 12: Graphs 783 | 784 | 1. Draw an interesting directed graph (with at least 6 nodes). 785 | 786 | ... 787 | 788 | 2. How many entries are in the Adjacency List representation of this graph? (Can you know without listing them?) 789 | 790 | ... 791 | 792 | 3. How many zeroes are in the Adjacency Matrix representation of this graph? 793 | 794 | ... 795 | 796 | Adjacency list has all outbound edges from a node at it's index 797 | 798 | 4. Walkthrough the Breadth-first and Depth-first traversals of this graph. Of the two trees that these traversals create, which has a greater height? 799 | 800 | Breadth-first search probably has the greatest height since it doesn't really have dead ends easily. --------------------------------------------------------------------------------