If you followed “Binary search isn’t about search” and “Binary search isn’t about search II” properly, the following statements should suffice as a summary:
Let’s complete the triptych. Take a wild guess what invariant we use for rightmost element binary search:
|
|
A motivating example
Consider again an array like
Clearly if we want to slide l
up to anywhere useful at all, L[0:l]
has to include at least a couple
of 0
s. r
labors under no such pretense. Hence why our equalities go loose-strict, or weak-strong,
for this third set of invariants.
What do we return now?
The ordinary b-search we wrote returns mid
; the leftwise b-search returns l
or r
, since they always converge to the same value by our invariants.
Rightwise search is very similar; l
and r
converge here as well, but we have to return the element immediately before them to get
the element we actually care about. So we will either return l - 1
or return r - 1
.
The code
|
|
Why r - 1
? I just like sticking with the theme of r
ightwise. There’s no difference.
Some useful mnemonic properties
The three approaches to binary search we have presented here all have properties people could quibble about. I like them regardless because a binary search I can reliably write by reasoning about invariants and inequalities from first principles is far more useful to me in practice than getting the absolute bleeding edge performance out of an algorithm before I have reason to think such a thing is warranted.
For example, we haven’t broached the topic of switching to sequential search when len(L)
is small. This is a common and wise optimization in languages like C, where you can
carefully reason about what actually is in the cache and what the CPU is likely to
retrieve the fastest; however, in a language like Python, it just doesn’t pay for the
casual DSA student to worry about things like this.
I have stuck with strong equalities where possible, both in our invariants and in our
while l < r:
loops, because I similarly find those easier to reason about than weak
ones. Maybe Real Analysis really did teach me something after all. ‘Til next time.