public interface Comparator { public int compare(E e1, E e2); //if e1 "<" e2, returns <0 //if e1 ">" e2, returns >0 //if e1 "=" e2, returns 0 } an unsorted ArrayList 1. add(e) add e to the end of the list. time: O(1) amortized 2. peek() iterate through the whole list finding the minimum time: O(n) 3. poll() call peek() remove the value by shifting all elements to the right of the min over to the left by one space. time: O(n) + O(n) = O(n) Less naive unsorted array list 1. add(e) when the first element is added, remember index 0 as the min. For any subsequent add, check if e < arr[min] and if it is, update min = size-1. time: O(1) amortized 2. peek() return array[min] time: O(1) 3. poll() 1. call peek() 2. remove minimum by shifting 3. find the previous minimum time: O(1) + O(n) + {depends <=O(n)} = O(n) Sorted Array list 1. add(e) insert e into its proper place in the sorted order (fastest way is the inner loop of insertion sort) time: O(n) time 2. peek() return array[size-1] O(1) 3. poll() remove index size-1 O(1) Java uses a binary minimum heap Def: A Binary tree is a structure where there exists only one path from the root to any node, and each node can have <=2 children Def: A complete binary tree is a binary tree where every level is completely filled (except for possibly the last row, but the last row must be filled left to right) Def: A binary min heap is a complete binary tree where every node obeys the binary min heap property: Every node must be >= its parent. (Every node must be <= its children) pseudocodes peek() return the root add(e) 1. put e at the end of the tree 2. Let i = that index 3. while(i is not the root && A[i]< A[parent(i)]) { swap(A, i, parent(i)); i = parent(i); } poll() 1. swap(A, root, bottom); 2. delete bottom 3. min = minimum(root, left, right); 4. if(root == min) return; 5. swap(A, root, min); 6. recursively continue with min as the new root; --------------------------------------------- unsorted array: 10 24 17 1 6 35 18 3 12 3 public static void heapSort(int[] arr, int heapSize) { buildMaxHeap(arr, heapSize); while(heapSize> 1) { swap(arr, 0, heapSize-1); fixMaxHeap(arr, heapSize-1); heapSize--; } } private static void buildHeap(int[] arr, int n) { for(int i=n/2; i>=0; i--) { fixMaxHeap(arr, i, n); } } private static void fixMaxHeap(int[] arr, int root, int n) { int left = 2*root+1; int right =2*root+2; int biggest = root; if(left < n && arr[root] < arr[left]) biggest = left; if(right < n && arr[biggest] < arr[right]) biggest= right; if(root==biggest) return; swap(arr, biggest, root); fixMaxHeap(arr, biggest, n); } } This is called heapsort and it takes O(nlogn) Why? building the heap takes O(n) repeatedly removing the max takes O(log n) per poll(), which in all takes O(n log n). Heapsort is optimal* (assuming elements need to be compared, and there are no special properties of the elements). some sorting algorithms: quicksort bubble sort merge sort selection sort insertion sort In order to prove the correctness of an algorithm, you must prove an invariant. Invariant for bubbleSort: after k iterations of the inner loop, the last k elements are in order. public static void insertionSort(int[] arr) { int n = arr.length; for(int pass = 1; pass < n; pass++){ int elem = arr[pass]; int i = pass-1; while(i>=0 && elem < arr[i]){ arr[i+1] = arr[i]; i--; } arr[i+1] = elem; } } Merging: Given 2 sorted arrays, how can we glue them into one big sorted array. A B 1 5 8 10 2 5 11 12 1 2 5(A) 5(B) 8 10 11 12 public static ArrayList not (ArrayList flags) { ArrayList answer; answer = new ArrayList<>(flags.size()); Iterator it = flags.iterator(); while(it.hasNext()) answer.add(!(it.next())); return answer; } public static void not (ArrayList flags) { ListIterator it = flags.listIterator(); while(it.hasNext()) it.set(!(it.next())); } }