1 / 56

Introduction to Algorithm Analysis Concepts

Introduction to Algorithm Analysis Concepts. 15-211 Fundamental Data Structures and Algorithms. Peter Lee January 15, 2004. Plan. Today Introduction to some basic concepts in the design of data structures Reading: For today: Chapter 5 and 7.1-7.3

orla-greene
Télécharger la présentation

Introduction to Algorithm Analysis Concepts

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Introduction to Algorithm Analysis Concepts 15-211 Fundamental Data Structures and Algorithms Peter Lee January 15, 2004

  2. Plan • Today • Introduction to some basic concepts in the design of data structures • Reading: • For today: Chapter 5 and 7.1-7.3 • For next time: Chapter 18 and 19

  3. Homework 1 is available! • See the Blackboard • Due Monday, Jan.19, 11:59pm

  4. A First Data Structure

  5. Lists of integers • Let’s start with a very simple data structure • Lists of integers, with operations such as: • create a new empty list • return the length of the list • add an integer to the end of the list • …

  6. Implementing lists • How shall we implement this? • What design process could we use? • One answer: • Think mathematically • Think inductively

  7. Induction • Recall proofs by induction: • If trying to prove that a property P(n) holds for all natural numbers 0, 1, 2, …, then • Prove the base case of P(0) • For n>0, assume P(n-1), show that P(n) holds

  8. Base case Inductive case Inductive definitions • A great deal of computer science can be defined inductively • For example, we can define the factorial function as follows: • fact(0) = 1 • fact(n) = n * fact(n-1), for n>0

  9. Implementing lists • How shall we implement this? • What design process could we use? • One answer: • Think mathematically • Think inductively

  10. Base case Inductive case Inductive definitions • An integer list is either • an empty list, or • an integer paired with an integer list

  11. Integer lists in Java The inductive definition gives us guidance on ways to implement integer lists in Java One possibility (not really the best): • An integer list is either • an empty list, or • an integer paired with an integer list use null define a new ListCell class

  12. Integer lists in Java public class List { int head; List tail; public List(int n, List l) { head = n; tail = l; } } • An integer list is either • an empty list, or • an integer paired with an integer list

  13. How about the length operation?

  14. Another inductive definition • The length of a list L is • 0, if L is the empty list • 1 + length of the tail of L, otherwise

  15. Implementing length() public class ListOps { public static int length (List l) { if (l==null) return 0; else return 1 + length(l.tail); } }

  16. The add operation • The add of n onto the end of list L is • the singleton list containing n, if L is the empty list • otherwise, a list whose head is the head of L and the tail is M • where M is the result of adding n onto the end of the tail of L

  17. Implementing add() public class ListOps { … public static List add (int n, List l) { if (l==null) return new List(n, null); else return new List(l.head, add(n, l.tail)); } }

  18. Running time • How much time does it take to compute length()? • and also add()?

  19. The “step” • In order to abstract from a particular piece of hardware, operating system, and language, we will focus on counting the number of steps of an algorithm • A “step” should execute in constant time • That is, it’s execution time should not vary much when the size of the input varies

  20. Constant-time operations public class ListOps { public static int length (List l) { if (l==null) return 0; else return 1 + length(l.tail); } } This is the only operation in length() that does not run in a constant amount of time. Hence, we want to know how many times this operation is invoked.

  21. Constant-time operations public static int length(List l) { if (l==null) return 0; else return 1 + length(l.tail); } Each call to length() requires at most a constant amount of time plus the time for a recursive call on the tail So, the “steps” we want are the number of recursive calls

  22. length() • How many steps for length()? • for a list with N elements, length() requires N-1 steps • Since length() requires ~N steps for an “input” of size N, we say that length() runs in linear time

  23. Why do we care about “steps”?

  24. Our goal • Our goal is to compare algorithms against each other • Not compute the “wall-clock” time • We will also want to know if an algorithm is “fast”, “slow”, or maybe so slow as to be impractical

  25. What about add()? public static List add(int n, List l) { if (l==null) return new List(n, null); else return new List(l.head, add(n, l.tail)); }

  26. Let’s Try Something a Bit Harder…

  27. Reverse • The reversal of a list L is: • L, if L is empty • otherwise, the head of L added to the end of M • where M is the reversal of the tail of L

  28. Implementing reverse() public static List reverse(List l) { if (l==null) return null; else { List r = reverse(l.tail); return add(l.head, r); } }

  29. How many steps? • How many “steps” does reverse take? • Think back to the inductive definition: • The reversal of a list L is: • L, if L is empty • otherwise, the head of L added to M • where M is the reversal of the tail of L

  30. Running time for reverse The running time is given by the following recurrence equation: t(0) = 0 t(n) = n + t(n-1) time required to reverse the tail Solving for t would tell us how many steps it takes to reverse a list time required to add head to the end

  31. Reverse t(0) = 0 public static List reverse(List l) { if (l==null) return null; else { List r = reverse(l.tail); return add(l.head, r); } } t(n) = n + t(n-1)

  32. Solving recurrence equations • A common first step is to use repeated substitution: • t(n) = n + t(n-1) • = n + (n-1) + t(n-2) • = n + (n-1) + (n-2) + t(n-3) • and so on… • = n + (n-1) + (n-2) + (n-3) + … + 1

  33. Klaus says that this is easy… t(n) = n + (n-1) + (n-2) + … 1 = n(n+1)/2 But how on earth did he come up with this beautiful little closed-form solution?

  34. Incrementing series • By the way, this is an arithmetic seires that comes up over and over again in computer science, because it characterizes many nested loops: for (i=1; i<n; i++) { for (j=1; j<i; j++) { f(); } }

  35. Mathematical handbooks • For really common series like this one, standard textbooks and mathematical handbooks will usually provide closed-form solutions. • So, one way is simply to look up the answer. • Another way is to try to think visually…

  36. Area of the leftovers:n/2 Area:n2/2 Visualizing it n … 3 So: n2/2 + n/2 = (n2+n)/2 = n(n+1)/2 2 1 0 1 2 3 … n

  37. Proving it • Yet another approach is to start with an answer or a guess, and then verify it by induction. • t(1) = 1(1+1)/2 = 1 • Inductive case: • for n>1, assume t(n-1) = (n-1)(n-1+1)/2 = (n2 – n) /2 • then t(n) = n + (n2 – n) /2 • = (n2 + n)/2 • = n(n+1)/2

  38. Summations • Arithmetic and geometric series come up everywhere in analysis of algorithms. • Some series come up so frequently that every computer scientist should know them by heart.

  39. Quadratic time • Very roughly speaking, • f(n) = n(n+1)/2 • grows no faster than • g(n) = n2 • In such cases, we say that reverse() runs in quadratic time • (we’ll be more precise about this later in the course)

  40. n2 is an upper bound

  41. How about Sorting? Everybody knows how to sort an array, but we have singly linked lists. As always, think inductively: sort(nil) = nil sort(L) = insert the head into the right place in sort(tail(L))

  42. Ordered Insert Need to insert element in order, in an already sorted lists. 2 5 10 20 50 12 2 5 12 10 20 50

  43. Code for ordered insert public List order_insert(int x, List l) { if (x <= l.head) return new List(x, l); List t = order_insert(x, l.tail); return new List(l.head, t); } The running time depends on the position of x in the new list. But in the worst case this could take n steps.

  44. Analysis of sort() sort(nil) = nil sort(L) = insert the head into the right place in sort(tail(L)) t(0) = 0 t(n) = n + t(n-1) which we already know to be “very roughly” n2, or quadratic time.

  45. Insertion sort This is yet another example of a doubly-nested loop… for i = 2 to n do insert a[i] in the proper place in a[1:i-1]

  46. How fast is insertion sort? We’ve essentially counted the number of computation steps in the worst case. But what happens if the elements are nearly sorted to begin with?

  47. A preview of some questions • Question: Insertion sort takes n2 steps in the worst case, and n steps in the best case. What do we expect in the average case? What is meant by “average”? • Question: What is the fastest that we could ever hope to sort? How could we prove our answer?

  48. Worst-case analysis • We’ll have much more to say, later in the course, about “worst-case” vs “average-case” vs “expected case” performance.

  49. Better sorting • The sorting algorithm we have just shown is called insertion sort. • It is OK for very small data sets, but otherwise is slow. • Later we will look at several sorting algorithms that run in many fewer steps.

  50. Quiz Break

More Related