Presentation is loading. Please wait.

Presentation is loading. Please wait.

Introduction to Algorithms: Verification, Complexity, and Searching Andy Wang Data Structures, Algorithms, and Generic Programming.

Similar presentations


Presentation on theme: "Introduction to Algorithms: Verification, Complexity, and Searching Andy Wang Data Structures, Algorithms, and Generic Programming."— Presentation transcript:

1

2 Introduction to Algorithms: Verification, Complexity, and Searching Andy Wang Data Structures, Algorithms, and Generic Programming

3 Lecture Overview Components of an algorithm Sequential search algorithms Binary search algorithms Proving algorithm correctness Computational complexity TVector Retrospective

4 Algorithm Components Required components Assumptions Asserted outcomes Body Proof Optional components Time complexity Space complexity

5 Sequential Search Goal Find a specified value in a collection of values Idea Walk through the collection and test each value A simple, commonly used, algorithm

6 Sequential Search Requirements A way to differentiate things in the collection A starting position A way to move on to the next thing in the collection A way to stop

7 Sequential Search Algorithm Assumptions Collection L of data of type T Can iterate through L with begin(), next(), end(); Outcomes Decide whether t is in L Return boolean (true/false)

8 Sequential Search Algorithm (2) Body (in pseudocode) for (T item = begin(L); item != end(L); item = next(L)) { if (t == item) return true; } if (t == item) return true; return false;

9 Binary Search Goal Find a value in a collection of values Idea Divide and conquer

10 Binary Search (2) Requirements Collection must be “array”-like Can use an index to jump to any array element Collection must be sorted Efficiency Very fast No extra space required

11 Binary Search—the idea You are heading down to an exotic restaurant… with something exotic on your mind… Chocolate……….Garlic……….Pasta … do not try this at home …

12 There are 8 items on the menu… sorted alphabetically… 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream

13 Binary Search—the idea The list is quite long…… it’s time to do a binary search… 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream

14 Binary Search—the idea 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream Search range: 0 - 7 Compare the middle element  Chocolate garlic pasta < Chocolate martini

15 Binary Search—the idea 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream Search range: 0 - 3 Compare the middle element  Chocolate garlic pasta > Blood pudding

16 Binary Search—the idea 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream Search range: 2 - 3 Compare the middle element  Chocolate garlic pasta == Chocolate garlic pasta

17 Binary Search—the idea Yum……………………………………

18 Binary Search Algorithm Three versions Binary_search Lower_bound Upper_bound

19 Binary Search Algorithm (2) Assumptions Collection L of data type of T with size sz L is sorted Element t of type T Outcomes Binary_search: true if t in L; false, otherwise Lower_bound: smallest j, where t <= L[j] Upper_bound: smallest j, where t < L[j]

20 Lower_bound Code unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } return low; }

21 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 7; while (0 < 7) { mid = (0 + 7) / 2 = 3; if (L[3] < t) { low = mid + 1; } else { high = mid; } return low;

22 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 7; while (0 < 7) { mid = (0 + 7) / 2 = 3; if (L[3] < t) { low = mid + 1; } else { high = mid; } return low;

23 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 3; while (0 < 3) { mid = (0 + 3) / 2 = 1; if (L[1] < t) { low = mid + 1; } else { high = mid; } return low;

24 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 3; while (0 < 3) { mid = (0 + 3) / 2 = 1; if (L[1] < t) { low = mid + 1; } else { high = mid; } return low;

25 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 2; high = 3; while (2 < 3) { mid = (2 + 3) / 2 = 2; if (L[2] < t) { low = mid + 1; } else { high = mid; } return low;

26 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 2; high = 3; while (2 < 3) { mid = (2 + 3) / 2 = 2; if (L[2] < t) { low = mid + 1; } else { high = mid; } return low;

27 Lower_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 2; high = 2; while (2 < 2) { … } return low = 2;

28 Upper_bound Code unsigned int upper_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { mid = (low + high) / 2; if (t < L[mid]) { high = mid; } else { low = mid + 1; } return low; }

29 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 7; while (0 < 7) { mid = (0 + 7) / 2 = 3; if (t < L[3]) { high = mid; } else { low = mid + 1; } return low;

30 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 7; while (0 < 7) { mid = (0 + 7) / 2 = 3; if (t < L[3]) { high = mid; } else { low = mid + 1; } return low;

31 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 3; while (0 < 3) { mid = (0 + 3) / 2 = 1; if (t < L[1]) { high = mid; } else { low = mid + 1; } return low;

32 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 0; high = 3; while (0 < 3) { mid = (0 + 3) / 2 = 1; if (t < L[1]) { high = mid; } else { low = mid + 1; } return low;

33 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 2; high = 3; while (2 < 3) { mid = (2 + 3) / 2 = 2; if (t < L[2]) { high = mid; } else { low = mid + 1; } return low;

34 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 2; high = 3; while (2 < 3) { mid = (2 + 3) / 2 = 2; if (t < L[2]) { high = mid; } else { low = mid + 1; } return low;

35 Upper_bound Code 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream t = “Chocolate Garlic Pasta” low = 3; high = 2; while (3 < 2) { … } return low = 3;

36 Binary_search Code unsigned int binary_search(T* L, unsigned sz, T t) { unsigned int lb = lower_bound(L, sz – 1, t); if (lb < sz) { if (t == L[lb]) { return true; } return false; }

37 If there are duplicate entries… 0. Baby beer 1. Blood pudding 2. Chocolate garlic pasta 3. Chocolate garlic pasta 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream Lower bound  Upper bound 

38 If t is not in L… 0. Baby beer 1. Blood pudding 2. Chocolate banana crepe 3. Chocolate martini 4. Death by Chocolate 5. Garlic ice cream 6. Popcorn-flavored jelly beans 7. Saffron ice cream Lower bound and upper bound 

39 Issues of Proof Correctness Termination Correct outcome Performance Time complexity Space complexity

40 Correctness and Loop Invariants Correctness Loop termination State when entering the loop State when exiting the loop Loop invariants Conditions that remain true for each iteration Mathematical induction

41 What can go wrong? for (j = 0; j < n; ++j) { compute(j); } void compute(unsigned int &j) { --j; } n < 0 at the beginning

42 Invariants—Sequential Search boolean sequential_search { for (T item = first(L); item != end(L); item = next(L)) { // item is not the final item in the collection // current item has not been examined  progress // L is finite if (t == item) { return true; } // t does not match the current item } if (t == item) { return true; } return false; }

43 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; }

44 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } t does not have to be L

45 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low –1 ] < t <= L[high] (if index is valid) } return low; } low = mid + 1 = (old_low + high)/2 + 1 <= (old_low + high)/2 + 1 < (high + high)/2 + 1 = high + 1 low < high + 1 low <= high

46 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low – 1] < t <= L[high] mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } high = mid = (low + old_high)/2 > (low + old_high)/2 - 1 > (low + low)/2 - 1 high > low – 1 high >= low

47 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } high – low = high – (mid + 1) = high – mid – 1 < high - mid = high – (old_low + high)/2 <= high – (old_low + high)/2 < high – (old_low + old_low)/2 = old_high – old_low high – low < old_high – old_low

48 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } high – low = high – (mid + 1) = high – mid – 1 < high - mid = high – (old_low + high)/2 <= high – (old_low + high)/2 = (high – old_low)/2 = (old_high – old_low)/2 high – low < (old_high – old_low)/2

49 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } high – low = mid – low = (low + old_high)/2 – low <= (low + old_high)/2 – low = (old_low + old_high)/2 – old_low < (old_high + old_high)/2 – old_low = old_high – old_low high – low < old_high – old_low

50 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } high – low = mid – low = (low + old_high)/2 – low <= (low + old_high)/2 – low = (old_high - low)/2 = (old_high - old_low)/2 high – low <= (old_high – old_low)/2

51 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } L[low - 1] = L[mid] < t Since high is not changed, t <= L[high]

52 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } Since low is unchanged, L[low] <= t L[high] = L[mid] >= t

53 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } Termination: (3) shows that the loop can terminate (4) shows progress

54 Invariants—Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { // (1) low < high // (2) L[low - 1] < t <= L[high] (if index is valid) mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } // (3) low <= high // (4) high – low has decreased // (5) L[low - 1] < t <= L[high] (if index is valid) } return low; } Return value: (5) smallest t <= L[j], since L[j = t

55 Computational Complexity Compares growth of two functions Independent of constant multipliers and lower-order effects Metrics “Big O” Notation “Big Omega” Notation “Big Theta” Notation

56 Big “O” Notation f(n) < O(g(n)) iff  c, n 0 > 0 | 0 = n 0 f(n) cg(n) n0n0

57 Big “Omega” Notation  (g(n)) < f(n) iff  c, n 0 > 0 | 0 = n 0 f(n) cg(n) n0n0

58 Big “Theta” Notation f(n) =  (g(n)) iff  c 1, c 2, n 0 > 0 | 0 = n 0 f(n) c 1 g(n) n0n0 c 2 g(n)

59 Examples 3n 2 + 17  (1),  (n) O(n 2 ), O(n 3 )  (n 2 )

60 Analogous to Real Numbers f(n) = O(g(n)) (a < b) f(n) =  (g(n)) (a > b) f(n) =  (g(n))(a = b)

61 Transitivity f(n) = O(g(n)) (a < b) f(n) =  (g(n)) (a > b) f(n) =  (g(n))(a = b) f(n) = O(g(n)) and g(n) = O(h(n)) f(n) = O(h(n))

62 Anti-symmetry f(n) = O(g(n)) (a < b) f(n) =  (g(n)) (a > b) f(n) =  (g(n))(a = b) f(n) = O(g(n)) iff g(n) =  (f(n))

63 Symmetry f(n) = O(g(n)) (a < b) f(n) =  (g(n)) (a > b) f(n) =  (g(n))(a = b) f(n) =  (g(n)) iff g(n) =  (f(n))

64 Reflexivity f(n) = O(g(n)) (a < b) f(n) =  (g(n)) (a > b) f(n) =  (g(n))(a = b) f(n) = O(f(n)), f(n) =  (f(n)), f(n) =  (f(n))

65 Dichotomy f(n) = O(g(n)) (a < b) f(n) =  (g(n)) (a > b) f(n) =  (g(n))(a = b) If f(n) = O(g(n)), g(n) =  (f(n)), f(n) =  (g(n))

66 Complexity Analysis Steps Find n = size of input Find an atomic activity to count Find f(n) = the number of atomic activities done by an input size of n Complexity of an algorithm = complexity of f(n)

67 Algorithm Complexity—Loops for (j = 0; j < n; ++j) { // 3 atomics } Complexity =  (3n) =  (n)

68 Loops with Break for (j = 0; j < n; ++j) { // 3 atomics if (condition) break; } Upper bound =  (3n) =  (n) Lower bound =  (3) =  (1) Complexity = O(n)

69 Loops in Sequence for (j = 0; j < n; ++j) { // 3 atomics } for (j = 0; j < n; ++j) { // 5 atomics } Complexity =  (3n + 5n) =  (n)

70 Nested Loops for (j = 0; j < n; ++j) { // 2 atomics for (k = 0; k < n; ++k) { // 3 atomics } Complexity =  ((2 + 3n)n) =  (n 2 )

71 Sequential Search for (T item = begin(L); item != end(L); item = next(L)) { if (t == item) return true; } if (t == item) return true; return false; Input size: n Atomic computation: comparison Complexity = O(n)

72 Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } return low; } Input size: n Atomic computation: comparison Complexity = k iterations x 1 comparison/loop  (log(n))

73 Iteration Count for Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } return low; } Iter # search space 1n 2n/2 3n/4 kn/2 (k-1) n/2 (k-1) = 1 n = 2 (k-1) log 2 (n) = k - 1

74 Iteration Count for Binary Search unsigned int lower_bound(T* L, unsigned max, T t) { unsigned int low = 0, mid, high = max; while (low < high) { mid = (low + high) / 2; if (L[mid] < t) { low = mid + 1; } else { high = mid; } return low; } n/2 (k-1) = 1 n = 2 (k-1) log 2 (n) = k - 1 log 2 (n) + 1 = k Complexity function f(n) = log(n) iterations x 1 comparison/loop =  (log(n))

75 TVector Retrospective Runtime complexity =  (1) PopBack(), Clear(), Front(), Back(), Empty() Size(), Capacity, [] Amortized runtime complexity =  (1) PushBack() Runtime complexity =  (n) Constructors, Destructor, Display(), Dump(), =


Download ppt "Introduction to Algorithms: Verification, Complexity, and Searching Andy Wang Data Structures, Algorithms, and Generic Programming."

Similar presentations


Ads by Google