C/C++ Arena

Step 3 of 6

lower_bound and upper_bound

In real code, use the standard library's binary searches on sorted ranges. They're correct, fast, and answer more useful questions than "is it there?":

#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> ages = {12, 15, 15, 15, 18, 21, 30, 42};

    auto lo = std::lower_bound(ages.begin(), ages.end(), 15);
    auto hi = std::upper_bound(ages.begin(), ages.end(), 15);
    std::cout << "15 appears " << (hi - lo) << " times, first at index " << (lo - ages.begin()) << "\n";

    auto adults = ages.end() - std::lower_bound(ages.begin(), ages.end(), 18);
    std::cout << adults << " are 18 or older\n";

    auto pos = std::lower_bound(ages.begin(), ages.end(), 20);
    std::cout << "20 would go at index " << (pos - ages.begin()) << ", before " << *pos << "\n";
    std::cout << std::binary_search(ages.begin(), ages.end(), 21) << std::binary_search(ages.begin(), ages.end(), 22) << "\n";
}
15 appears 3 times, first at index 1
4 are 18 or older
20 would go at index 5, before 21
10

Picture it

For the value 15 in 12 15 15 15 18:

 12  15  15  15  18
     ^           ^
lower_bound   upper_bound

The elements equal to x are exactly [lower_bound, upper_bound). Subtracting the iterators counts them.

Counting a range

The number of values v with lo <= v <= hi is:

upper_bound(hi) - lower_bound(lo)

lower_bound(lo) is the first value that's at least lo; upper_bound(hi) is the first value past hi. Everything between them is in range. Two binary searches, O(log n), no matter how many values match. If lo > hi, the result would be negative, so return 0 in that case.

Your turn: write long count_in_range(const std::vector<int>& sorted, int lo, int hi) counting values v with lo <= v <= hi.

Previous: Binary search Next: Two pointers