how to check whether a set has element(s) in certain range in C++

2.3k views Asked by At

I need to check if a std::set contains element/elements in a range. For example, if the set is a set<int> {1, 2, 4, 7, 8}, and given an int interval [3, 5] (inclusive with both endpoints), I need to know if it has elements in the set. In this case, return true. But if the interval is [5, 6], return false. The interval may be [4, 4], but not [5, 3].

Looks like I can use set::lower_bound, but I am not sure whether this is the correct approach. I also want to keep the complexity as low as possible. I believe using lower_bound is logarithmic, correct?

2

There are 2 answers

1
James McNellis On BEST ANSWER

You can use lower_bound and upper_bound together. Your example of testing for elements between 3 and 5, inclusive, could be written as follows:

bool contains_elements_in_range = s.lower_bound(3) != s.upper_bound(5);

You can make the range inclusive or exclusive on either end by switching which function you are using (upper_bound or lower_bound):

s.upper_bound(2) != s.upper_bound(5); // Tests (2, 5]
s.lower_bound(3) != s.lower_bound(6); // Tests [3, 6)
s.upper_bound(2) != s.lower_bound(6); // Tests (2, 6)

Logarithmic time is the best you can achieve for this, since the set is sorted and you need to find an element in the sorted range, which requires a dichotomic search.

0
ruakh On

If you're certain that you're going to use a std::set, then I agree that its lower_bound method is the way to go. As you say, it will have logarithmic time complexity.

But depending what you're trying to do, your program's overall performance might be better if you use a sorted std::vector and the standalone std::lower_bound algorithm (std::lower_bound(v.begin(), v.end(), 3)). This is also logarithmic, but with a lower constant. (The downside, of course, is that inserting elements into a std::vector, and keeping it sorted, is usually much more expensive than inserting elements into a std::set.)