2

So.. I am trying to find the maximum value of a vector and its position in the vector. I am using a for loop, and it's working fine. My problem is, that if the maximum value appears more than once, I want to know all the positions in which it appears in the vector.. So, how could I manage this? So far, this is the code I am using: (the vector called v has elements that I read from a file but I will not add that part of the code)

std::vector<double>v;
double maxvalue;
int position=0;
maxvalue = v[0];

for (unsigned int i=0; i<v.size(); i++){
    if (v[i]> maxvalue){
        maxvalue=v[i];
        position= i;
    }
}
Eduardo Pascual Aseff
  • 1,149
  • 2
  • 13
  • 26

4 Answers4

3

You could modify your approach to keep a vector of indices where the maximum occurred:

#include <cfloat>
#include <iostream>
#include <utility>
#include <vector>

std::pair<double, std::vector<std::size_t>> FindMaxElements(std::vector<double> const& v)
{
    std::vector<std::size_t> indices;
    double current_max = -DBL_MAX;

    for (std::size_t i = 0; i < v.size(); ++i)
    {
        if (v[i] > current_max)
        {
            current_max = v[i];
            indices.clear();
        }

        if (v[i] == current_max)
        {
            indices.push_back(i);
        }
    }

    return std::make_pair(current_max, indices);
}

int main()
{
    auto result = FindMaxElements({1, 4, 7, 2, 7, 3});
    std::cout << "max: " << result.first << '\n';
    std::cout << "indices: ";
    for (auto i : result.second)
         std::cout << i << ' ';
}

Output

max: 7
indices: 2 4
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
2

Here is a two-pass version using the standard library (whereas it might be cleaner without it):

#include <vector>
#include <algorithm>

int main()
{
    std::vector<double> v {/* fill it*/ };
    std::vector<int> pos;

    auto it = std::max_element(std::begin(v), std::end(v));
    while (it != std::end(v))
    {
        pos.push_back(std::distance(std::begin(v), it));
        it = std::find(std::next(it), std::end(v), *it);
    }
    //...
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
davidhigh
  • 14,652
  • 2
  • 44
  • 75
1

The function template below, find_maximums(), returns an std::vector<size_t> that contains the positions where the maximums are in the input vector. Note that it returns an empty vector of indexes if the input vector is empty.

template<typename T>
auto find_maximums(const std::vector<T>& v) {
   std::vector<size_t> indexes;

   for (auto it_max = std::max_element(v.begin(), v.end()); it_max != v.end();
        it_max = std::find(it_max+1, v.end(), *it_max))
   {
      auto index = std::distance(v.begin(), it_max);
      indexes.push_back(index);
   }

   return indexes;
}

As an example of use:

auto main() -> int {
   std::vector<int> v = {11, 7, 3, 11, 0, 7, 1, 11, 11};
   auto max_indexes = find_maximums(v);

   if (max_indexes.empty())
      return 1;

   std::cout << "max: " << v[max_indexes.front()] << std::endl;
   std::cout << "max at positions: ";
   for (auto idx: max_indexes)
      std::cout << idx << ' ';
   std::cout << '\n';
}

It outputs:

max: 11
max at positions: 0 3 7 8
JFMR
  • 23,265
  • 4
  • 52
  • 76
0

Passing a couple of iterators and a comparator

template <class It,
          class Comp = std::less<typename std::iterator_traits<It>::value_type>>
auto max_elements_indices(It first, It last, Comp cmp = Comp{})
{
    // This function returns a vector of indices, so to get the maximum, the caller
    // should first check if the returned vector is empty and then use one of
    // those indices to retrieve the value.
    std::vector<std::size_t> indices;
    if (first == last)
        return indices;

    // Using the first element instead of a sentinel value is easier to generalize
    indices.push_back(0);
    auto value = *first;

    for (auto i = std::next(first); i != last; ++i)
    {
        // The most common case should be an element below the maximum
        if ( cmp(*i, value) )
            continue;
        else
        {
            if ( cmp(value, *i) )
            {
                value = *i;
                indices.clear();
            }
            indices.push_back(std::distance(first, i));
        }
    }
    return indices;
}

It is testable here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bob__
  • 12,361
  • 3
  • 28
  • 42
  • `indices.push_back(*first);` is storing the *value* denoted by `first`, not the *index* of the value. – Remy Lebeau Apr 21 '20 at 20:42
  • Now you are are pushing the *iterators themselves*, not *indexes*. To store *indexes*, you would need to either 1) save the `first` iterator to a local variable and then use `std::distance()`, or 2) declare a local variable for the current index that is incremented while iterating. – Remy Lebeau Apr 21 '20 at 21:01
  • @RemyLebeau Correct. Again, thanks. Time to call it the day, I guess. – Bob__ Apr 21 '20 at 21:19