Lecture Notes for Math182: Algorithms Draft: Last Revised July 28, 2020
Total Page:16
File Type:pdf, Size:1020Kb
Lecture notes for Math182: Algorithms Draft: Last revised July 28, 2020 Allen Gehret Author address: Department of Mathematics, University of California, Los Ange- les, Los Angeles, CA 90095 E-mail address: [email protected] Contents List of Figures vii Introduction ix Prerequisites xi Conventions and notation xi Acknowledgements xii Chapter 1. Discrete mathematics and basic algorithms 1 1.1. Induction 1 1.2. Summations 2 1.3. Triangular number algorithms 5 1.4. Common functions 10 1.5. Fibonacci numbers 15 1.6. Exercises 22 Chapter 2. Asymptotics 27 2.1. Asymptotic notation 27 2.2. Properties of asymptotic notation 31 2.3. The Euclidean Algorithm 34 2.4. Exercises 38 Chapter 3. Sorting algorithms 41 3.1. Insertion sort 41 3.2. Merge sort 45 3.3. Lower bound on comparison-based sorting 52 3.4. Exercises 54 Chapter 4. Divide-and-Conquer 57 4.1. The maximum-subarray problem 57 4.2. The substitution method 61 4.3. The recursion-tree method 65 4.4. The master method 70 4.5. Strassen's algorithm for matrix multiplication 71 Chapter 5. Data structures 73 5.1. Heaps 73 5.2. Heapsort 79 5.3. Priority queues 80 5.4. Stacks and queues 83 Chapter 6. Dynamic programming 89 iii iv CONTENTS 6.1. Rod cutting 89 6.2. Matrix-chain multiplication 96 Chapter 7. Greedy algorithms 103 7.1. An activity-selection problem 103 Chapter 8. Elementary graph algorithms 107 8.1. Representations of graphs 107 8.2. Breadth-first search 107 8.3. Depth-first search 114 8.4. Minimum spanning trees 118 Chapter 9. Single-source shortest paths 125 9.1. Single-source shortest paths 125 9.2. The Bellman-Ford algorithm 128 Appendix A. Pseudocode conventions and Python 131 A.1. Pseudocode conventions 131 A.2. Python 133 Bibliography 135 Index 137 Abstract The objectives of this class is are as follows: (1) Survey various well-known algorithms which solve a variety of common problems which arise in computer science. This includes reviewing the mathematical background involved in the algorithms and when possi- ble characterizing the algorithms into one of several algorithm paradigms (greedy, divide-and-conquer, dynamic,...). (2) Use mathematics to analyze and determine the efficiency of an algorithm (i.e., does the running time scale linearly, scale quadratically, scale expo- nentially, etc. with the size of the input, etc.). (3) Use mathematics to prove the correctness of an algorithm (i.e., prove that it correctly does what it is supposed to do). Portions of these notes are based on [6], [1], and [5]. Any and all questions, com- ments, typos, suggestions concerning these notes are enthusiastically welcome and greatly appreciated. Last revised July 28, 2020. 2010 Mathematics Subject Classification. Primary . The first author is supported by the National Science Foundation under Award No. 1703709. v List of Figures 3.1 Here we trace through Insertion-Sort with input A = h3; 2; 1i. The first part of the code processes the 2 in the second spot, inserting it before the 3 in the first spot, moving 3 over one spot to the right. The next part of the code processes the 1 in the third spot, inserting it before the 2 and the 3, thus moving the 2 and the 3 over one spot to the right each. 43 3.2 Here we trace through Merge(A; 5; 6; 8) where A[5 :: 8] = h2; 3; 1; 4i. This means that we will merge h2; 3i with h1; 4i, so we should end up with A[5 :: 8] = h1; 2; 3; 4i, which we do. At the top we show the result of lines 1-11, after we have copied A[5; 6] into L[1; 2] and A[6; 7] into R[1; 2]. 48 3.3 Here we consider the recursion tree of Merge-Sort in three levels of detail: (1) With just the top level of recursion shown, (2) With the top two levels of recursion shown, and (3) all three levels of recursion shown. 53 3.4 Here we show the decision tree for the Insertion-Sort algorithm run on an input of size 3. The leaves of the tree represent the permutation of the original input needed in order to sort the original input. We also show an example of a particular path of the decision tree based on the input h7; 9; 5i which requires the permutation h3; 1; 2i in order to be put into sorted for h5; 7; 9i. 55 4.1 This shows the three locations where we may find our maximum subarray: contained in the left half A[low :: mid], contained in the right half A[mid + 1 :: hight], or split between both halves and crossing the midpoint (of the form A[i : : j] where i ≤ mid and j ≥ mid + 1) 59 4.2 Finding the two subarrays which, when joined together, constitutes the maximum subarray of A[low :: high] which crosses the midpoint 60 4.3 The recursion tree for T (n) = 3T (n=4) + cn2 67 4.4 The recursion tree for T (n) = T (n=3) + T (2n=3) + cn 69 5.1 Here we illustrate a heap in two ways. First as an abstract nearly-complete binary tree. Second as an array. Note that this heap is neither a max-heap nor a min-heap. Furthermore, only the subarray A[1 : : A:heap-size] represents the heap, the rest of the subarray A[A:heap-size + 1 : : A:length] is not part of the heap. 74 5.2 Here we illustrate a max-heap in two ways. First as a binary tree. Second as an array. The tree has height 3, the node 8 (corresponding to A[4]) has height 1. 75 vii viii LIST OF FIGURES 5.3 Here we call Max-Heapify(A; 2). First it exchanges A[2] with A[4] (its left child). Then it recursively calls Max-Heapify(A; 4), which exchanges A[4] with A[9] (its right child). Then it is finished and the heap with root 2 is now a max-heap. 77 5.4 Here we call Build-Max-Heap on the array A = h4; 1; 3; 2; 16; 9; 10; 14; 8; 7i. It iteratively calls Max-Heapify(5); Max-Heapify(4);:::; Max-Heapify(1). 78 5.5 Here we call Heapsort on a certain array A. First we apply Build-Max-Heap(A) to get a max-heap. Then we iteratively take the max and put it at the end of the heap, make the heap one element smaller, then call Max-Heapify on the smaller heap to find the next max. 81 5.6 Here we call Heap-Increase-Key(A; i; 15). First this changes the key A[i] = 4 to A[i] = 15. Next it bubbles up the key 15 until the max-heap property is satisfied. 83 5.7 We start with a nonempty stack S. Then we call in succession Push(S; 17), Push(S; 3), and Pop(S), which returns 3. At the end, 3 is still part of the array S, but not part of the stack S. 85 5.8 We start with a nonempty queue and call in succession Enqueue(Q; 17); Enqueue(Q; 3); Enqueue(5) which adds 17, 3, and 5 to the back of the queue, in that order. Then we call Dequeue(Q) which returns 15 and advances the head of the queue to the next element after 15. 86 6.1 First we show the full recursion tree for Cut-Rod(p; 4). Next we show the subproblem graph for n = 4, which is like a collapsed version of the recursion tree. 94 6.2 Here we find the optimal parenthesization for the chain hA1;A2;:::;Ani, where the array of dimensions is p = h30; 35; 15; 5; 10; 20; 25i. We compute iteratively the optimal solutions to the subproblems Ai::j and store the answers in the two-dimensional array m[i; j]. We also store in s[i; j] the index k which achieves the optimal solution for m[i; j]. This allows us to reconstruct the optimal parenthesization. 100 8.1 Here we show how both an undirected graph and a directed graph can be represented with either an adjacency-list or with an adjacency-matrix. 108 8.2 An example of BFS. The black vertices are the ones with double circles and the white vertices have distance 1. All other vertices are gray. 111 8.3 Here we show the result of DFS on a directed graph. Below that is an illustration of the intervals of the discovery times for each nodes. Finally, we show the directed graph with all tree and forward edges going down and all back edges going up. 117 8.4 An example of a minimum-spanning tree 119 8.5 Here we show a cut (S; V n S) which respects A (the bold edges). We illustrate this cut in two different ways. We also indicate a light edge for the cut. 120 8.6 The proof of Theorem 8.4.1 121 Introduction What is an algorithm? This is a tough question to provide a definitive answer to, but since it is the subject of this course, we will attempt to say a few words about it. Generally speaking, an algorithm is an unambiguous sequence of instructions which accomplishes some- thing. As human beings, we are constantly following algorithms in our everyday life. For instance, here is an algorithm for eating a banana: (Step 1) Peel banana.