## Exercises
#### Section 2.1
1. Use Binary Search, Recursion ([Algorithm 2.1](LiB0015.html#149)) to search for the integer 120 in the following list (array) of integers. Show the actions step by step.
![](https://box.kancloud.cn/4ed0c7a6cd51d9f55e6dc7370ebf0225_325x18.jpg)
2. Suppose that, even unrealistically, we are to search a list of700 million items using Binary Search, Recursion ([Algorithm 2.1](LiB0015.html#149)). What is the maximum number of comparisons that this algorithm must perform before finding a given item or concluding that it is not in the list?
3. Let us assume that we always perform a successful search. That is, in [Algorithm 2.1](LiB0015.html#149) the item *x* can always be found in the list *S.* Improve [Algorithm 2.1](LiB0015.html#149) by removing all unnecessary operations.
4. Show that the worst-case time complexity for Binary Search ([Algorithm 2.1](LiB0015.html#149)) is given by
![](https://box.kancloud.cn/2d94a15a2b8730aa6dc67f06cbf9e5d5_149x21.jpg)
When *n* is not restricted to being a power of 2. *Hint*: First show that the recurrence equation for ***W*** (*n*) is given by
![](https://box.kancloud.cn/22f4823268ae773959eb8bd3e896e6a2_292x63.jpg)
To do this, consider even and odd values of *n* separately. Then use induction to solve the recurrence equation.
5. Suppose that, in [Algorithm 2.1](LiB0015.html#149) (line 4), the splitting function is changed to *mid* = *low*:. Explain the new search strategy. Analyze the performance of this strategy and show the results using order notation.
6. Write an algorithm that searches a sorted list of *n* items by dividing it into three sublists of almost *n*/3 items. This algorithm finds the sublist that might contain the given item and divides it into three smaller sublists of almost equal size. The algorithm repeats this process until it finds the item or concludes that the item is not in the list. Analyze your algorithm and give the results using order notation.
7. Use the divide-and-conquer approach to write an algorithm that finds the largest item in a list of *n* items. Analyze your algorithm, and show the results in order notation.
#### Section 2.2
1. Use Mergesort ([Algorithms 2.2](LiB0016.html#158) and [2.4](LiB0016.html#169)) to sort the following list. Show the actions step by step.
![](https://box.kancloud.cn/c93cf1f3b05e2d7dbae9cc06fe01c078_299x16.jpg)
2. Give the tree of recursive calls in Exercise 8.
3. Write for the following problem a recursive algorithm whose worst-case time complexity is not worse than Θ (*n* ln *n*). Given a list of *n* distinct positive integers, partition the list into two sublists, each of size *n*/2, such that the difference between the sums of the integers in the two sublists is maximized. You may assume that *n* is a multiple of 2.
4. Write a nonrecursive algorithm for Mergesort ([Algorithms 2.2](LiB0016.html#158) and [2.4](LiB0016.html#169)).
5. Show that the recurrence equation for the worst-case time complexity for Mergesort ([Algorithms 2.2](LiB0016.html#158) and [2.4](LiB0016.html#169)) is given by
![](https://box.kancloud.cn/a69266739fac73e839aa5a378b9d30b8_315x37.jpg)
when *n* is not restricted to being a power of 2.
6. Write an algorithm that sorts a lists of *n* items by dividing it into three sublists of about *n*/3 items, sorting each sublist recursively and merging the three sorted sublists. Analyze your algorithm, and give the results under order notation.
#### Section 2.3
1. Given the recurrence relation
![](https://box.kancloud.cn/58a0d88c252ef35c86abe6b2c7a69e85_308x81.jpg)
find *T* (625).
2. Consider algorithm *solve* given below. This algorithm solves problem *P* by finding the output (solution) *O* corresponding to any input *I.*
```
void solve (input I, output& O)
{
if (size (I) == 1)
find solution O directly;
else{
partition I into 5 inputs I1, I2, I3, I4, I5, where
size (Ij) = size (I)/3 for j = 1, ..., 5;
for (j = 1; j < = 5; j++)
solve (Ij, Oj);
combine O1, O2, O3, O4, O5 to get O for P with input I;
}
}
```
Assume *g* (*n*) basic operations for partitioning and combining and no basic operations for an instance of size 1.
1. Write a recurrence equation *T*(*n*) for the number of basic operations needed to solve *P* when the input size is *n*.
2. What is the solution to this recurrence equation if *g*(*n*) ∊ Θ (*n*)? (Proof is not required.)
3. Assuming that *g* (*n*) = *n*2, solve the recurrence equation exactly for *n* = 27.
4. Find the general solution for *n* a power of 3.
3. Suppose that, in a divide-and-conquer algorithm, we always divide an instance of size *n* of a problem into 10 subinstances of size *n*/3, and the dividing and combining steps take a time in Θ (*n*2). Write a recurrence equation for the running time *T* (*n*), and solve the equation for *T* (*n*).
4. Write a divide-and-conquer algorithm for the Towers of Hanoi problem. The Towers of Hanoi problem consists of three pegs and *n* disks of different sizes. The object is to move the disks that are stacked, in decreasing order of their size, on one of the three pegs to a new peg using the third one as a temporary peg. The problem should be solved according to the following rules: (1) when a disk is moved, it must be placed on one of the three pegs; (2) only one disk may be moved at a time, and it must be the top disk on one of the pegs; and (3) a larger disk may never be placed on top of a smaller disk.
1. Show for your algorithm that *S* (*n*) = 2*n*− 1. (Here *S* (*n*) denotes the number of steps (moves), given an input of *n* disks.)
2. Prove that any other algorithm takes at least as many moves as given in part (a).
5. When a divide-and-conquer algorithm divides an instance of size *n* of a problem into subinstances each of *size* *n/c*, the recurrence relation is typically given by
![](https://box.kancloud.cn/380abf465e32ccb962977ef7d067a96e_324x82.jpg)
where *g* (*n*) is the cost of the dividing and combining processes, and *d* is a constant. Let *n* = *ck*.
1. Show that
![](https://box.kancloud.cn/91b4bb945375d17f2a5f1c958d8a5779_303x60.jpg)
2. Solve the recurrence relation given that *g* (*n*) ∊ Θ (*n*).
#### Section 2.4
1. Use Quicksort ([Algorithm 2.6](LiB0018.html#177)) to sort the following list. Show the actions step by step.
![](https://box.kancloud.cn/3529fefc8f9ff8b90b2669497d3a7683_299x16.jpg)
2. Give the tree of recursive calls in Exercise 19.
3. Show that if
![](https://box.kancloud.cn/480a5f5be62219cd06ae7c37e0e06586_400x41.jpg)
then
![](https://box.kancloud.cn/384296865d0b4d01fb8d633a127ef001_291x42.jpg)
This result is used in the discussion of the worst-case time complexity analysis of [Algorithm 2.6](LiB0018.html#177) (Quicksort).
4. Verify the following identity
![](https://box.kancloud.cn/2f7a26f37b4efabb1fff50924b6bc190_352x56.jpg)
This result is used in the discussion of the average-case time complexity analysis of [Algorithm 2.6](LiB0018.html#177) (Quicksort).
5. Write a nonrecursive algorithm for Quicksort ([Algorithm 2.6](LiB0018.html#177)). Analyze your algorithm, and give the results using order notation.
6. Assuming that Quicksort uses the first item in the list as the pivot item:
1. Give a list of *n* items (for example, an array of 10 integers) representing the worst-case scenario.
2. Give a list of *n* items (for example, an array of 10 integers) representing the best-case scenario.
#### Section 2.5
1. Show that the number of additions performed by [Algorithm 1.4](LiB0008.html#34) (Matrix Multiplication) can be reduced to *n*3− *n*2 after a slight modification of this algorithm.
2. In Example 2.4, we gave Strassen's product of two 2 × 2 matrices. Verify the correctness of this product.
3. How many multiplications would be performed in finding the product of two 64 × 64 matrices using the standard algorithm?
4. How many multiplications would be performed in finding the product of two 64 × 64 matrices using Strassen's method ([Algorithm 2.8](LiB0019.html#201))?
5. Write a recurrence equation for the modified Strassen's algorithm developed by Shmuel Winograd that uses 15 additions/subtractions instead of 18. Solve the recurrence equation, and verify your answer using the time complexity shown at the end of [Section 2.5](#ch02lev3sec5).
#### Section 2.6
1. Use [Algorithm 2.10](LiB0020.html#218) (Large Integer Multiplication 2) to find the product of 1253 and 23,103.
2. How many multiplications are needed to find the product of the two integers in Exercise 30?
3. Write algorithms that perform the operations
*u* × 10*m*; *u* divide 10*m*; *u* rem 10*m*,
where *u* represents a large integer, *m* is a nonnegative integer, divide returns the quotient in integer division, and rem returns the remainder. Analyze your algorithms, and show that these operations can be done in linear time.
4. Modify [Algorithm 2.9](LiB0020.html#214) (Large Integer Multiplication) so that it divides each *n*-digit integer into
1. three smaller integers of *n*/3 digits (you may assume that *n* = 3*k*).
2. four smaller integers of *n*/4 digits (you may assume that *n* = 4*k*).
Analyze your algorithms, and show their time complexities in order notation.
#### Section 2.7
1. Implement both Exchange Sort and Quicksort algorithms on your computer to sort a list of *n* elements. Find the lower bound for *n* that justifies application of the Quicksort algorithm with its overhead.
2. Implement both the standard algorithm and Strassen's algorithm on your computer to multiply two *n* × *n* matrices (*n* = 2*k*). Find the lower bound for *n* that justifies application of Strassen's algorithm with its overhead.
3. Suppose that on a particular computer it takes 12*n*2μs to decompose and recombine an instance of size *n* in the case of [Algorithm 2.8](LiB0019.html#201) (Strassen). Note that this time includes the time it takes to do all the additions and subtractions. If it takes *n*3μs to multiply two *n* × *n* matrices using the standard algorithm, determine thresholds at which we should call the standard algorithm instead of dividing the instance further. Is there a unique optimal threshold?
#### Section 2.8
1. Use the divide-and-conquer approach to write a recursive algorithm that computes *n*!. Define the input size (see Exercise 34 in [Chapter 1](LiB0008.html#16)), and answer the following questions. Does your function have an exponential time complexity? Does this violate the statement of case 1 given in [Section 2.8](#ch02lev3sec8)
2. Suppose that, in a divide-and-conquer algorithm, we always divide an instance of size *n* of a problem into *n* subinstances of size *n*/3, and the dividing and combining steps take linear time. Write a recurrence equation for the running time *T* (*n*), and solve this recurrence equation for *T* (*n*). Show your solution in order notation.
### Additional Exercises
1. Write an efficient algorithm that searches for a value in an *n* × *m* table (two-dimensional array). This table is sorted along the rows and columns—that is,
![](https://box.kancloud.cn/fb4f9d413dbfb28f5540fe7071dc61f6_227x50.jpg)
2. Suppose that there are *n* = 2*k* teams in an elimination tournament, in which there are *n*/2 games in the first round, with the *n*/2 = 2*k*−1 winners playing in the second round, and so on.
1. Develop a recurrence equation for the number of rounds in the tournament.
2. (b) How many rounds are there in the tournament when there are 64 teams?
3. Solve the recurrence equation of part (a).
3. Write a recursive Θ (*n* lg *n*) algorithm whose parameters are three integers *x*, *n*, and *p,* and which computes the remainder when *xn* is divided by *p.* For simplicity, you may assume that *n* is a power of 2—that is, that *n* = 2*k* for some positive integer *k.*
4. Use the divide-and-conquer approach to write a recursive algorithm that finds the maximum sum in any contiguous sublist of a given list of *n* real values. Analyze your algorithm, and show the results in order notation.
- Table of Contents
- BackCover
- Foundations of Algorithms Using C++ Pseudocode, Third Edition
- Preface
- Chapter Contents
- Pedagogy
- Course Outlines
- Acknowledgments
- Errors
- Chapter 1: Algorithms - Efficiency, Analysis, and Order
- 1.2 The Importance of Developing Efficient Algorithms
- 1.3 Analysis of Algorithms
- 1.4 Order
- 1.5 Outline of This Book
- Exercises
- Chapter 2: Divide-and-Conquer
- 2.1 Binary Search
- 2.2 Mergesort
- 2.3 The Divide-and-Conquer Approach
- 2.4 Quicksort (Partition Exchange Sort)
- 2.5 Strassen's Matrix Multiplication Algorithm
- 2.6 Arithmetic with Large Integers
- 2.7 Determining Thresholds
- 2.8 When Not to Use Divide-and-Conquer
- Exercises
- Chapter 3: Dynamic Programming
- 3.1 The Binomial Coefficient
- 3.2 Floyd's Algorithm for Shortest Paths
- 3.3 Dynamic Programming and Optimization Problems
- 3.4 Chained Matrix Multiplication
- 3.5 Optimal Binary Search Trees
- 3.6 The Traveling Salesperson Problem
- Exercises
- Chapter 4: The Greedy Approach
- 4.1 Minimum Spanning Trees
- 4.2 Dijkstra's Algorithm for Single-Source Shortest Paths
- 4.3 Scheduling
- 4.4 Huffman Code
- 4.5 The Greedy Approach versus Dynamic Programming: The Knapsack Problem
- Exercises
- Chapter 5: Backtracking
- 5.2 The n-Queens Problem
- 5.3 Using a Monte Carlo Algorithm to Estimate the Efficiency of a Backtracking Algorithm
- 5.4 The Sum-of-Subsets Problem
- 5.5 Graph Coloring
- 5.6 The Hamiltonian Circuits Problem
- 5.7 The 0-1 Knapsack Problem
- Exercises
- Chapter 6: Branch-and-Bound
- 6.1 Illustrating Branch-and-Bound with the 0 - 1 Knapsack problem
- 6.2 The Traveling Salesperson Problem
- 6.3 Abductive Inference (Diagnosis)
- Exercises
- Chapter 7: Introduction to Computational Complexity - The Sorting Problem
- 7.2 Insertion Sort and Selection Sort
- 7.3 Lower Bounds for Algorithms that Remove at Most One Inversion per Comparison
- 7.4 Mergesort Revisited
- 7.5 Quicksort Revisited
- 7.6 Heapsort
- 7.6.1 Heaps and Basic Heap Routines
- 7.6.2 An Implementation of Heapsort
- 7.7 Comparison of Mergesort, Quicksort, and Heapsort
- 7.8 Lower Bounds for Sorting Only by Comparison of Keys
- 7.8.1 Decision Trees for Sorting Algorithms
- 7.8.2 Lower Bounds for Worst-Case Behavior
- 7.8.3 Lower Bounds for Average-Case Behavior
- 7.9 Sorting by Distribution (Radix Sort)
- Exercises
- Chapter 8: More Computational Complexity - The Searching Problem
- 8.1 Lower Bounds for Searching Only by Comparisons of Keys
- 8.2 Interpolation Search
- 8.3 Searching in Trees
- 8.4 Hashing
- 8.5 The Selection Problem: Introduction to Adversary Arguments
- Exercises
- Chapter 9: Computational Complexity and Interactability - An Introduction to the Theory of NP
- 9.2 Input Size Revisited
- 9.3 The Three General Problem Categories
- 9.4 The Theory of NP
- 9.5 Handling NP-Hard Problems
- Exercises
- Chapter 10: Number-Theoretic Algorithms
- 10.1 Number Theory Review
- 10.2 Computing the Greatest Common Divisor
- 10.3 Modular Arithmetic Review
- 10.4 Solving Modular Linear Equations
- 10.5 Computing Modular Powers
- 10.6 Finding Large Prime Numbers
- 10.7 The RSA Public-Key Cryptosystem
- Exercises
- Chapter 11: Introduction to Parallel Algorithms
- 11.1 Parallel Architectures
- 11.2 The PRAM Model
- Exercises
- Appendix A: Review of Necessary Mathematics
- A.2 Functions
- A.3 Mathematical Induction
- A.4 Theorems and Lemmas
- A.5 Logarithms
- A.6 Sets
- A.7 Permutations and Combinations
- A.8 Probability
- Exercises
- Appendix B: Solving Recurrence Equations - With Applications to Analysis of Recursive Algorithms
- B.2 Solving Recurrences Using the Characteristic Equation
- B.3 Solving Recurrences by Substitution
- B.4 Extending Results for n, a Power of a Positive Constant b, to n in General
- B.5 Proofs of Theorems
- Exercises
- Appendix C: Data Structures for Disjoint Sets
- References
- Index
- Index_B
- Index_C
- Index_D
- Index_E
- Index_F
- Index_G
- Index_H
- Index_I
- Index_J
- Index_K
- Index_L
- Index_M
- Index_N
- Index_O
- Index_P
- Index_Q
- Index_R
- Index_S
- Index_T
- Index_U
- Index_V
- Index_W-X
- Index_Y
- Index_Z
- List of Figures
- List of Tables
- List of Algorithms, Examples, and Theorems
- List of Sidebars