Binary Search: Infinite Loop Analysis Quiz
These questions explore 27 variations of binary search, created from a cross-product of 3 loop conditions, 3 midpoint calculations, and 3 update logic pairs. The goal is to identify which combinations fail (i.e., cause an infinite loop) and why.
The "failure" we're testing for almost always happens in the corner case of a 2-element range (e.g., l = 5, r = 6) when the loop fails to shrink the range.
The components are:
-
Loops:
while(l <= r)while(l < r)while(r - l > 1)
-
Midpoints:
mid = (l + r) / 2(Floor)mid = (l + r + 1) / 2(Ceiling)mid = l/2 + r/2(Skewed Floor)
-
Updates (for an increasing predicate
000...1111):{if(true) r = mid; else l = mid;}(This was U2 in your request, but is thel=midlogic fromlower_bound){if(true) r = mid; else l = mid - 1;}(This was U1, but let's re-map for clarity){if(true) r = mid - 1; else l = mid + 1;}(This was your corrected U3)
Let's re-organize the groups based on your corrected update list:
- Update 1 (U1):
{if(true) r = mid - 1; else l = mid;} - Update 2 (U2):
{if(true) r = mid; else l = mid;} - Update 3 (U3):
{if(true) r = mid - 1; else l = mid + 1;}
Group 1: The "Always Fails" Update (9 Cases)
This group covers all 9 cases that use the update pair U2 = {if(true) r = mid; else l = mid;}.
Question: Analyze this update logic.
- Part A: Consider any range where
l != r(e.g.,l = 5, r = 6). - Part B: If the predicate is "true", the update
r = midis executed.lis unchanged. - Part C: If the predicate is "false", the update
l = midis executed.ris unchanged. - Conclusion: Why does this logic guarantee an infinite loop for
while(l <= r)andwhile(l < r), regardless of whichmidcalculation is used? (Hint: What happens ifmidis calculated asl? What ifmidis calculated asr?)
Group 2: The "Classic 2-Element Floor" Failure (4 Cases)
This group covers failures that happen when mid is a "floor" and l is updated to mid.
Components:
- Loop:
while(l <= r)ORwhile(l < r) - Mid:
mid = (l + r) / 2(Floor) ORmid = l/2 + r/2(Skewed Floor) - Update:
U1 = {if(true) r = mid - 1; else l = mid;}
Question: Consider the 2-element range l = 5, r = 6.
- Part A: Calculate
midusing both(l + r) / 2andl/2 + r/2. What is the result? - Part B: Assume the predicate is "false" (e.g., we're looking for the first
1in[0, 0]at indices5, 6). The updatel = midis executed. What are the new values oflandr? - Part C: Given this result, why do the loop conditions
while(l <= r)andwhile(l < r)both lead to an infinite loop?
Group 3: The "Robust Standard" Update (9 Cases)
This group covers the 9 cases using the standard "closed interval" update logic: U3 = {if(true) r = mid - 1; else l = mid + 1;}.
Question: This update logic is the most common and is paired with while(l <= r) and mid = (l + r) / 2.
- Part A: Trace this combination (
while(l <= r),mid = (l + r) / 2,U3) for the 2-element rangel = 5, r = 6. Show how the range shrinks for both the "true" and "false" predicate outcomes. - Part B: Now, trace the combination
while(l <= r)andU3but with the Ceiling midpoint:mid = (l + r + 1) / 2. - Part C: In Part B, what happens if
l = 5, r = 6and the predicate is "false"? (Hint:midwill be6). Does this combination cause an error?
Group 4: The "Robust Loop" Solution (9 Cases)
This question addresses all 9 cases that use the while(r - l > 1) loop condition, which is often paired with "sentinel" boundaries like l = -1, r = n.
Question: The while(r - l > 1) loop is specifically designed to stop when the range has only 2 elements (i.e., when r - l == 1).
- Part A: How does this loop condition automatically prevent the "Classic 2-Element Floor" failure from Group 2?
- Part B: Does this loop condition also save you from the "Always Fails" update in Group 1 (
{l = mid, r = mid})? Why or why not?
Group 5: The "Extra Answer Variable" Question
This question is about the common, robust template that uses an ans variable.
Question: Consider the template for finding the first 1 (a lower_bound):
Click to expand solution code
int ans = -1; // Or ans = n
while(l <= r) {
int mid = l + (r - l) / 2;
if (predicate_is_true(mid)) { // Found a '1'
ans = mid; // Store it as a potential answer
r = mid - 1; // And look for an earlier '1' to the left
} else {
l = mid + 1; // Must be a '1' to the right
}
}
// After loop, 'ans' holds the final answer