## Exercises
#### Section 8.1
1. Let us assume that a search does not start at the beginning of a list when the Sequential Search algorithm ([Alogrithm 1.1](LiB0008.html#27)) is used, but rather starts wherever the list index was left at the termination of the preceding search. Let us further assume that the item for which we are searching is selected randomly and independently of the destinations of previous searches. Under these assumptions, what would be the average number of comparisons?
2. Let *S* and *T* be two arrays of *m* and *n* elements, respectively. Write an algorithm that finds all the common elements and stores them in an array *U.* Show that this can be done in Θ (*n + m*) time.
3. Improve the Binary Search algorithm ([Alogrithm 1.5](LiB0009.html#38)) assuming a successful search. Analyze your algorithm and show the results using order notation.
4. Show that, if *x* is in the array and is equally probable to be in each of the array slots, the average-case time complexity for Binary Search ([Alogrithm 1.5](LiB0009.html#38)) is bounded approximately by
![](https://box.kancloud.cn/a43e3c353d3bc930e24f6628d60fa955_213x24.jpg)
*Hint*: By [Lemma 8.4](LiB0068.html#783), for some *k, n* − (2*k* − 1) is the number of nodes at the bottom level. The contribution to the *TND* for those nodes is equal to (*n* − 2*k* − 1) (*k* + 1). Add this expression to (*k* − 1) 2*k* + 1 (the formula established in the average-case analysis of Binary Search) to obtain the *TND* for the decision tree.
5. Suppose that all of the following 2*n* + 1 possibilities are equally probable:
![](https://box.kancloud.cn/c08c45cece970865877ae9db0c63b0a3_400x91.jpg)
Show that the average-case time complexity of the Binary Search algorithm ([Alogrithm 1.5](LiB0009.html#38)) is bounded approximately by
![](https://box.kancloud.cn/8cc833488129ae8ddc9c3c8383bc6353_249x39.jpg)
*Hint*: See the hint for Exercise 4.
6. Complete the proof of [Lemma 8.6](LiB0068.html#786).
#### Section 8.2
1. Implement the Binary Search, Interpolation Search, and Robust Interpolation Search algorithms on your system and study their best-case, average-case, and worst-case performances using several problem instances.
2. Show that the average-case time complexity of Interpolation Search is in Θ (lg (lg *n*)), assuming the keys are uniformly distributed and that search key *x* is equally probable to be in each of the array slots.
3. Show that the worst-case time complexity of Interpolation Search is in Θ ((lg *n*)2), assuming the keys are uniformly distributed and that search key *x* is equally probable to be in each of the array slots.
#### Section 8.3
1. Write an algorithm that finds the largest key in a binary search tree. Analyze your algorithm, and show the results using order notation.
2. [Theorem 8.3](LiB0070.html#801) states that, for a successful search, the average search time over all inputs containing *n* keys, using binary search trees, is in Θ (lg *n*). Show that this result still holds if we consider an unsuccessful search as well.
3. Write an algorithm that deletes a node from a binary search tree considering all possible cases. Analyze your algorithm and show the results using order notation.
4. Write an algorithm that creates a 3–2 tree from a list of keys. Analyze your algorithm and show the results using order notation.
5. Write an algorithm that lists all the keys in a 3–2 tree in their natural order. Analyze your algorithm and show the results using order notation.
#### Section 8.4
1. Another clash (collision) resolution strategy is linear probing. In this strategy, all the elements are stored in the array of buckets (hash table). In the case of a clash, the table is searched for the next available (free) bucket. Show how linear probing resolves clashes that occur in the problem instance of [Figure 8.8](LiB0071.html#809). (Linear probing is also known as closed hashing.)
2. Discuss the advantages and disadvantages of the two clash resolution strategies, open hashing and linear probing (see Exercise 15).
3. Write an algorithm to delete an element from a hash table that uses linear probing as its clash resolution strategy. Analyze your algorithm and show the results using order notation.
4. A rehashing scheme known as double hashing uses a second hash function in case of a clash. If the first hash function is *h* and the second hash function is *s*, the entire sequence of positions of the hash table that will be checked for an available bucket is given by the following equality, where *pi* is the *i*th position in the sequence:
![](https://box.kancloud.cn/0b4dfe2fe6e0bf33c7c65fedffae8e41_400x24.jpg)
(% returns the remainder when the first operand is divided by the second.) Define a second hash function for the problem instance of [Figure 8.8](LiB0071.html#809) and show the table after all the keys have been inserted into the hash table.
#### Section 8.5
1. Modify [Alogrithm 8.4](LiB0072.html#828) (Find Smallest and Largest Keys by Pairing Keys) so that it works when *n* (the number of keys in the given array) is odd and show that its time complexity is given by
![](https://box.kancloud.cn/76feaf60ed65ca9a3509adb454cb40e3_179x85.jpg)
2. Complete the proof of [Theorem 8.8](LiB0072.html#838). That is, show that a deterministic algorithm that finds the smallest and largest of *n* keys only by comparisons of keys must in the worst case do at least (3*n* − 3) /2 comparisons if *n* is odd.
3. Write an algorithm for the method discussed in [Section 8.5.3](LiB0072.html#840) for finding the second-largest key in a given array.
4. Show that for *n* in general, the total number of comparisons needed by the method discussed in [Section 8.5.3](LiB0072.html#840) for finding the second-largest key in a given array is
![](https://box.kancloud.cn/445ba85647a7e52bf052917e595a1ea2_177x19.jpg)
5. Show that the median of five numbers can be found by making six comparisons.
6. Use induction to show that the worst-case time complexity of [Alogrithm 8.6](LiB0072.html#856) (Selection Using the Median) is bounded approximately as follows:
![](https://box.kancloud.cn/20a5c119239e54a1cd787cbfa2e02b08_107x21.jpg)
7. Show that for an arbitrary *m* (group size), the recurrence for the worst-case time complexity of [Alogrithm 8.6](LiB0072.html#856) (Selection Using the Median) is given by
![](https://box.kancloud.cn/63abd64d68552e01ff91d87597d4d401_340x50.jpg)
where *a* is a constant. This is Recurrence 8.2 in [Section 8.5.4](LiB0072.html#848).
8. Use induction to show that *W (n*) ∊ Ω (*n* lg *n*) for the following recurrence. This is Recurrence 8.2 in [Section 8.5.4](LiB0072.html#848) where *m* (group size) is 3.
![](https://box.kancloud.cn/80b6e739ad205bb3fa7dab7adcf17307_274x47.jpg)
9. Show that the constant *c* in the inequality
![](https://box.kancloud.cn/afee3a8b5243728dc4bd3f281049f9bb_103x20.jpg)
in the expected-value time complexity analysis of [Alogrithm 8.7](LiB0072.html#864) (Probabilistic Selection) cannot be less than 4.
10. Implement [Algorithms 8.5](LiB0072.html#849), [Algorithms 8.6](LiB0072.html#856), and [Algorithms 8.7](LiB0072.html#864) (Selection algorithms for finding the *k*th-smallest key in an array) on your system and study their best-case, average-case, and worst-case performances using several problem instances.
11. Write a probabilistic algorithm that determines whether an array of *n* elements has a majority element (the element that appears the most). Analyze your algorithm and show the results using order notation.
#### Additional Problems
1. Suppose a very large sorted list is stored in external storage. Assuming that this list cannot be brought into internal memory, develop a searching algorithm that looks for a key in this list. What major factor(s) should be considered when an external search algorithm is developed? Define the major factor(s), analyze your algorithm, and show the results using order notation.
2. Discuss the advantages of using each of the following instead of the other:
1. A binary search tree with a balancing mechanism
2. A 3–2 tree
3. Give at least two examples of situations in which hashing is not appropriate.
4. Let *S* and *T* be two arrays of *n* numbers that are already in nondecreasing order. Write an algorithm that finds the median of all 2*n* numbers whose time complexity is in Θ (lg *n).*
5. Write a probabilistic algorithm that factors any integer using the functions *prime* and *factor.* Function *prime* is a boolean function that returns "true" if a given integer is a prime number and returns "false" if it is not. Function **factor** is a function that returns a nontrivial factor of a given composite integer. Analyze your algorithm, and show the results using order notation.
6. List the advantages and disadvantages of all the searching algorithms discussed in this chapter.
7. For each of the searching algorithms discussed in this chapter, give at least two examples of situations in which the algorithm is the most appropriate.
- 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