In C++, upper_bound() is a built-in function used to find the first element in a sorted range that is strictly greater than a given value. It implements binary search algorithm so it requires that the range is either sorted or at least partitioned with respect to the given element.
Let's take a look at an example:
C++
// C++ program to illustrate the use of std::upper_bound
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> v = {10, 20, 30, 40, 50};
// Finding upper bound for value 30 in vector v
cout << *upper_bound(v.begin(), v.end(), 30);
return 0;
}
Syntax of upper_bound()
The upper_bound() function is defined inside the <algorithm> header file.
upper_bound (first, last, val, comp);
Parameters:
- first: Iterator to the first element in the range.
- last: Iterator to the theoretical element just after the last element in the range.
- val: Value to be compared.
- comp (optional): Binary function that accepts and compares val with an element in the range. By default, it returns true if the val is smaller than the element in the range, false otherwise.
Return Value:
- Returns an iterator to the smallest number greater than val.
- Returns iterator to the end of the range if all the elements are smaller than or equal to val.
Note: The behavior of the upper_bound() is undefined if the array is not sorted or at least partitioned with respect to the given value.
The upper_bound function is useful for finding elements in sorted ranges. The C++ Course offers detailed lessons on STL algorithms, including how to use upper_bound effectively in your projects.
Examples of upper_bound()
The upper_bound() function is an interesting function that can be used for number of applications. The below examples demonstrate some of its common uses.
Find Upper Bound in an Array
C++
// C++ program to find the lower bound of a value in a
// vector using std::upper_bound()
#include <bits/stdc++.h>
using namespace std;
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int n = sizeof(arr)/sizeof(arr[0]);
// Finding upper bound for value 30 in array arr
cout << *upper_bound(arr, arr + n, 30);
return 0;
}
Time Complexity: O(log n), where n
is the number of elements in the array.
Auxiliary Space: O(1).
Use upper_bound() with Custom Comparator
C++
// C++ program to illustrate how to use custom
// comparator with std::upper_bound() function
#include <bits/stdc++.h>
using namespace std;
bool comp(const string &a, const string &b) {
return lexicographical_compare(a.begin(), a.end(),
b.begin(), b.end(), [](char c1, char c2) {
return tolower(c1) < tolower(c2);
});
}
int main() {
vector<string> v = {"Apple", "banana", "Cherry",
"date", "Elderberry"};
// Finding upper bound of "Avocado"
auto ub = upper_bound(v.begin(), v.end(), "Avocado",
comp);
if (ub != v.end())
cout << *ub;
else
cout << "Upper bound not found!";
return 0;
}
Time Complexity: O(log n), where n is the number of elements in the vector.
Auxiliary Space: O(1)
Explanation: We need to use the custom comparator function to perform the case insensitive search as the default comparator treats the uppercase and lowercase differently.
Check for an Element in a Sorted Vector
C++
// C++ Program to check if the element exists in a
// vector using upper_bound()
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> v = {10, 20, 30, 40, 50};
int val = 40;
// Finding the upper bound
auto it = upper_bound(v.begin(), v.end(), val);
// Chekcing if val exists or not
if (it != v.begin() && *(--it) == val)
cout << val << " is found.";
else
cout << val << " is NOT found.";
return 0;
}
Time Complexity: O(log n), where n is the number of elements in vector.
Auxiliary Space: O(1)
Explanation: Unlike lower_bound() function, the upper_bound() function never returns the iterator to the matching value if found, it always returns the iterator to the value just after the matching value if it exists. So, to check if the given value exists, we need to decrement the iterator return by the upper_bound() and then compare.
Count Elements Smaller and Larger than a Value
C++
// C++ Program to count the elements smaller and larger
// than a value in a vector using upper_bound()
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> v = {10, 20, 30, 40, 50};
int val = 30;
// Finding the upper bound of val in v
auto ub = upper_bound(v.begin(), v.end(), val);
// Finding the number of smaller elements
cout << "No. of Smaller Elements: " << ub - v.begin()
<< endl;
// Finding the number of larger elements
cout << "No. of Larger Elements: " << v.end() - ub;
return 0;
}
OutputNo. of Smaller Elements: 3
No. of Larger Elements: 2
Time Complexity: O(log n), where n is the number of elements in vector.
Auxiliary Space: O(1)
Explanation: Counts elements based on the position returned by upper_bound().
Finding Upper Bound in a Set
C++
// C++ program to find the upper bound of a value in
// a set using std::upper_bound()
#include <bits/stdc++.h>
using namespace std;
int main() {
set<int> s = {10, 20, 30, 40, 50};
// Finding upper bound for value 30 in set s
auto it = upper_bound(s.begin(), s.end(), 30);
cout << *it;
return 0;
}
Time Complexity: O(n)
Space Complexity: O(1)
Explanation: The time complexity is O(n) for the set is because it doesn't provide random access to its elements. So, the upper_bound() function have to increment it sequentially to find the middle element (part of binary search algorithm) each time leading to increased time complexity. However, set have their own specialized version named as set::upper_bound() method.