Table of contents
1.
Introduction
2.
"std::max_element() Syntax
3.
Parameters
4.
Return value
5.
More Examples of std::max_element()
5.1.
1. Finding the maximum element in an array:
5.2.
2. Finding the maximum element in a container using a custom comparison function
5.3.
3. Finding the maximum element in a range specified by iterators
6.
Working of std::max_element()
7.
Complexity
7.1.
Time Complexity
7.2.
Space Complexity
8.
Exceptions
9.
Frequently Asked Questions
9.1.
What happens if the range passed to std::max_element() is empty? 
9.2.
Can std::max_element() be used with custom types? 
9.3.
How does std::max_element() handle multiple occurrences of the maximum element? 
10.
Conclusion
Last Updated: Nov 25, 2024
Easy

max_element in C++ STL

Author Gaurav Gandhi
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

The std::max_element() is a built-in function in C++ that is part of the <algorithm> header. It helps us in finding the maximum element in a given range of elements, like an array or a container. This function takes the start & end iterators of the range as parameters and returns an iterator pointing to the maximum element within that range. If there are multiple occurrences of the maximum element, the iterator returns points to the first occurrence. std::max_element() provides a simple and efficient way to find the maximum value in a container without the need for manual iteration & comparison. 

max_element in C++ STL

In this article, we will discuss the syntax, parameters, return value, examples, working, and time complexity of std::max_element() in C++.

"std::max_element() Syntax

The syntax for using std::max_element() in C++ is:

ForwardIterator max_element(ForwardIterator first, ForwardIterator last);
ForwardIterator max_element(ForwardIterator first, ForwardIterator last, Compare comp);


The first version of std::max_element() takes two parameters:

  • `first`: The iterator pointing to the first element of the range.
     
  • `last`: The iterator pointing to the position one past the last element of the range.
     

The second version of std::max_element() takes an additional parameter:

`comp`: A binary function or function object that accepts two elements of the range as arguments & returns true if the first element is considered less than the second element.
 

Note: The `ForwardIterator` type represents an iterator that can be used to traverse the range in a forward direction. It can be an iterator of a container such as `std::vector`, `std::array`, or a pointer to an array.

Parameters

std::max_element() takes the parameters mentioned below:


1. `first` (required): This parameter represents the iterator pointing to the first element of the range in which we want to find the maximum element. It can be the beginning iterator of a container (such as `std::vector`, `std::array`) or a pointer to the first element of an array.
 

2. `last` (required): This parameter represents the iterator pointing to the position one past the last element of the range. It can be the end iterator of a container or a pointer to one past the last element of an array. The range specified by `[first, last)` is a half-open range, meaning that the `last` iterator is not included in the range.
 

3. `comp` (optional): This parameter is a binary function or function object that defines the comparison criteria for determining the maximum element. It takes two elements of the range as arguments & returns `true` if the first element is considered less than the second element according to the desired comparison logic. If `comp` is not provided, the default `operator<` is used for comparison.
 

Let’s look at an example to understand the use of std::max_element() with and without the `comp` parameter:

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

int main() {
    std::vector<int> nums = {5, 2, 9, 1, 7};

    // Using default comparison (operator<)
    auto maxIt = std::max_element(nums.begin(), nums.end());
    std::cout << "Maximum element: " << *maxIt << std::endl;

    // Using custom comparison function
    auto maxIt2 = std::max_element(nums.begin(), nums.end(), [](int a, int b) {
        return a > b;
    });
    std::cout << "Maximum element (custom comparison): " << *maxIt2 << std::endl;

    return 0;
}
You can also try this code with Online C++ Compiler
Run Code


Output:

Maximum element: 9
Maximum element (custom comparison): 1


In the first case, std::max_element() uses the default `operator<` for comparison & returns an iterator pointing to the maximum element (9).


In the second case, a custom comparison function is provided using a lambda expression. The lambda function returns `true` if `a > b`, effectively finding the minimum element instead of the maximum. As a result, the iterator returned points to the minimum element (1).

Return value

std::max_element() returns an iterator pointing to the maximum element in the specified range. The return type of std::max_element() is the same as the type of the input iterators (`ForwardIterator`).

If the range is empty, the function returns the `last` iterator.

If multiple elements in the range have the maximum value, the iterator returned points to the first occurrence of the maximum element.

Let’s discuss an example that shows the return value of std::max_element():

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

int main() {
    std::vector<int> nums = {5, 2, 9, 1, 9, 7};

    auto maxIt = std::max_element(nums.begin(), nums.end());

    if (maxIt != nums.end()) {
        std::cout << "Maximum element: " << *maxIt << std::endl;
        std::cout << "Index of maximum element: " << std::distance(nums.begin(), maxIt) << std::endl;
    } else {
        std::cout << "The range is empty." << std::endl;
    }

    return 0;
}
You can also try this code with Online C++ Compiler
Run Code


Output:

Maximum element: 9
Index of maximum element: 2


In this example, std::max_element() returns an iterator pointing to the first occurrence of the maximum element (9) in the `nums` vector. We can dereference the iterator using `*maxIt` to access the maximum element itself.


We can also use the std::distance() function to find the index of the maximum element by calculating the distance between the beginning of the range & the iterator returned by std::max_element().


Always remember: It's important to check if the returned iterator is equal to the `last` iterator before accessing the maximum element. If the range is empty, dereferencing the `last` iterator would be undefined behavior.

More Examples of std::max_element()

Now, let’s take a few more examples to understand the use of std::max_element() in different situations:

1. Finding the maximum element in an array:

#include <algorithm>
#include <iostream>
int main() {
    int arr[] = {10, 5, 8, 20, 3};
    int size = sizeof(arr) / sizeof(arr[0]);

    int* maxIt = std::max_element(arr, arr + size);

    std::cout << "Maximum element: " << *maxIt << std::endl;

    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output:

Maximum element: 20

2. Finding the maximum element in a container using a custom comparison function

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

// Custom comparison function
bool compareAbsolute(int a, int b) {
    return std::abs(a) < std::abs(b);
}

int main() {
    std::vector<int> nums = {-5, 2, -9, 1, 7};

    auto maxIt = std::max_element(nums.begin(), nums.end(), compareAbsolute);

    std::cout << "Maximum element (absolute value): " << *maxIt << std::endl;

    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output:

Maximum element (absolute value): -9

3. Finding the maximum element in a range specified by iterators

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

int main() {
    std::vector<int> nums = {5, 2, 9, 1, 7};

    auto maxIt = std::max_element(nums.begin() + 1, nums.end() - 1);

    std::cout << "Maximum element in the range [1, 3): " << *maxIt << std::endl;

    return 0;
}
You can also try this code with Online C++ Compiler
Run Code


Output:

Maximum element in the range [1, 3): 9


These examples explain clearly how std::max_element() can be used with arrays, custom comparison functions, & specific ranges within a container.

Working of std::max_element()

Now, let's learn how std::max_element() works internally to find the maximum element in a range.
 

1. The function starts by initializing two iterators, `first` and `last`, which represent the beginning and end of the range, respectively.
 

2. It assigns the `first` iterator to a variable, say `largest`, which will keep track of the iterator pointing to the maximum element found so far.
 

3. Then, it iterates over the range using a loop, starting from the second element (the element after `first`) up to the `last` element.
 

4. For each element in the range, it compares the element with the element pointed to by the `largest` iterator.

   - If the current element is greater than the element pointed to by `largest`, it updates `largest` to point to the current element.

   - If the `comp` function is provided, it uses `comp` to perform the comparison instead of the default `operator<`.
 

5. After the loop ends, the `largest` iterator will be pointing to the maximum element in the range according to the specified comparison criteria.
 

6. Finally, the function returns the `largest` iterator.


Let’s take a look at a more simplified implementation of std::max_element() to understand its working:

template <class ForwardIterator>
ForwardIterator max_element(ForwardIterator first, ForwardIterator last) {
    if (first == last) {
        return last;
    }

    ForwardIterator largest = first;
    ++first;

    for (; first != last; ++first) {
        if (*largest < *first) {
            largest = first;
        }
    }

    return largest;
}


In this code: 

  • The function first checks if the range is empty by comparing `first` and `last`. If they are equal, it means the range is empty, and the function returns `last`.
     
  • It initializes `largest` to `first`, assuming the first element is the maximum element so far.
     
  • It starts a loop from the second element (`++first`) and iterates until `first` reaches `last`.
     
  • Inside the loop, it compares the element pointed to by `largest` with the current element pointed to by `first` using `operator<`.
     
  •   - If the current element is greater, it updates `largest` to `first`.
     
  • After the loop ends, `largest` will be pointing to the maximum element, and the function returns `largest`.
     

Note: This is a simplified implementation for understanding purposes. The actual implementation of std::max_element() in the C++ Standard Library is more optimized and handles additional cases.

Complexity

Let's analyze the time and space complexity of std::max_element().

Time Complexity

  • std::max_element() performs a single pass over the range, comparing each element with the current maximum element.
     
  • The number of comparisons made is proportional to the number of elements in the range.
     
  • Therefore, the time complexity of std::max_element() is O(n), where n is the number of elements in the range.
     
  • This means that the function's running time grows linearly with the size of the input range.

Space Complexity

  • std::max_element() uses only a constant amount of extra space.
     
  • It does not allocate any additional memory that grows with the size of the input range.
     
  • The space required is used for the iterators and any temporary variables, which are independent of the range size.
     
  • Therefore, the space complexity of std::max_element() is O(1), indicating constant space usage.

Exceptions

std::max_element() does not throw any exceptions by itself. However, there are a few scenarios where exceptions can be thrown indirectly:

1. If the comparison function (`comp`) throws an exception during the comparison of elements, that exception will propagate out of std::max_element().
 

2. If the iterators passed to std::max_element() are invalid or do not form a valid range, the behavior is undefined. This can lead to exceptions or unexpected results, depending on the implementation.
 

3. If the elements in the range do not meet the requirements of the comparison function (e.g., if `comp` expects a certain type and the elements are of a different type), it may result in compilation errors or unexpected behavior.
 

Let’s look at an example that shows an exception thrown by the comparison function:

#include <algorithm>
#include <iostream>
#include <vector>
// Custom comparison function that throws an exception
bool compareWithException(int a, int b) {
    if (a < 0 || b < 0) {
        throw std::runtime_error("Negative values not allowed");
    }
    return a < b;
}

int main() {
    std::vector<int> nums = {5, 2, 9, -1, 7};

    try {
        auto maxIt = std::max_element(nums.begin(), nums.end(), compareWithException);
        std::cout << "Maximum element: " << *maxIt << std::endl;
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what() << std::endl;
    }


    return 0;
}
You can also try this code with Online C++ Compiler
Run Code


Output:

Exception caught: Negative values not allowed


In this example, the custom comparison function `compareWithException` throws a `std::runtime_error` exception when it encounters negative values. When std::max_element() is called with this comparison function and the `nums` vector containing a negative value, the exception is thrown and caught in the `catch` block.

Note: It's important to ensure that the comparison function is well-defined and does not unexpectedly throw exceptions. Also, make sure to handle any potential exceptions thrown by the comparison function appropriately.

Frequently Asked Questions

What happens if the range passed to std::max_element() is empty? 

If the range is empty, std::max_element() returns the last iterator.

Can std::max_element() be used with custom types? 

Yes, std::max_element() can be used with custom types as long as they have a valid comparison operator or a custom comparison function is provided.

How does std::max_element() handle multiple occurrences of the maximum element? 

If there are multiple occurrences of the maximum element, std::max_element() returns an iterator pointing to the first occurrence.

Conclusion

In this article, we discussed the std::max_element() function in C++, which is used to find the maximum element in a given range. We covered its syntax, parameters, and return value with examples to understand the implementation properly. We also looked into the working of std::max_element(), analyzed its time and space complexity, and discussed the exceptions that can be thrown indirectly. std::max_element() provides a convenient and efficient way to find the maximum element in a container or range, which makes it an important function for any C++ programmer.

You can also check out our other blogs on Code360.

Live masterclass