Usando std::max_element en un vector

4 minutos de lectura

avatar de usuario
sináptico

estoy tratando de usar std::min_element y std::max_element para devolver los elementos mínimo y máximo en un vector de dobles. A mi compilador no le gusta cómo intento usarlos actualmente y no entiendo el mensaje de error. Por supuesto, podría escribir mi propio procedimiento para encontrar el mínimo y el máximo, pero me gustaría entender cómo usar las funciones.

#include <vector>
#include <algorithm>

using namespace std;

int main(int argc, char** argv) {

    double cLower, cUpper;
    vector<double> C;

    // Code to insert values in C is not shown here

    cLower = min_element(C.begin(), C.end());
    cUpper = max_element(C.begin(), C.end());

    return 0;
}

Aquí está el error del compilador:

../MIXD.cpp:84: error: cannot convert '__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >' to 'double' in assignment
../MIXD.cpp:85: error: cannot convert '__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >' to 'double' in assignment

¿Qué estoy haciendo mal?

  • Tenga en cuenta que si está usando C ++ 11, solo puede usar std::minmax_element.

    – GManNickG

    15 de abril de 2012 a las 4:51

  • @GManNickG: No conocía esa función. He agregado una nota a mi respuesta para incorporar esto ya que el comportamiento es diferente.

    – johnsyweb

    17 de abril de 2012 a las 2:53

min_element y max_element devuelve iteradores, no valores. Así que tú necesitas *min_element... y *max_element....

  • Un iterador es un puntero en el sentido de que apunta a cosas. Pero puede o no ser un puntero ordinario. Por ejemplo, si un iterador se refiere a un objeto en una lista, incrementarlo hace que apunte al siguiente objeto en la lista. Incrementar un puntero ordinario solo hace eso para colecciones como un vector que garantiza almacenar su contenido en direcciones de memoria de secuencia.

    –David Schwartz

    15 de abril de 2012 a las 1:51

  • en caso de que el vector esté vacío *max_element genera error. ¿Hay alguna solución para manejar este problema? En este momento compruebo si el vector está vacío o no y luego uso *max_element

    – Moj

    6 de diciembre de 2013 a las 15:22

  • Creo que esa es la mejor solución. De todos modos, debe manejar el caso de manera especial, porque no hay un valor razonable que pueda devolverse.

    –David Schwartz

    6 de diciembre de 2013 a las 18:09

  • @Moj: puedes verificar el iterador contra C.end().

    – intelfx

    10/06/2014 a las 15:50

avatar de usuario
johnsyweb

Como han dicho otros, std::max_element() y std::min_element() devolver iteradoresque deben ser desreferenciado para obtener el valor.

La ventaja de devolver un iterador (en lugar de solo el valor) es que le permite determinar el posición del (primer) elemento en el contenedor con el valor máximo (o mínimo).

Por ejemplo (usando C++ 11 por brevedad):

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

int main()
{
    std::vector<double> v {1.0, 2.0, 3.0, 4.0, 5.0, 1.0, 2.0, 3.0, 4.0, 5.0};

    auto biggest = std::max_element(std::begin(v), std::end(v));
    std::cout << "Max element is " << *biggest
        << " at position " << std::distance(std::begin(v), biggest) << std::endl;

    auto smallest = std::min_element(std::begin(v), std::end(v));
    std::cout << "min element is " << *smallest
        << " at position " << std::distance(std::begin(v), smallest) << std::endl;
}

Esto produce:

Max element is 5 at position 4
min element is 1 at position 0

Nota:

Usando std::minmax_element() como se sugiere en los comentarios anteriores, puede ser más rápido para grandes conjuntos de datos, pero puede dar resultados ligeramente diferentes. los valores para mi ejemplo anterior sería el mismo, pero la posición del elemento “max” sería 9 ya que…

Si varios elementos son equivalentes al elemento más grande, se devuelve el iterador al último elemento.

  • @synaptik: Esto también debería funcionar con otros tipos de contenedores 🙂

    – johnsyweb

    15 de abril de 2012 a las 22:46

min/max_element devuelve el iterador al elemento min/max, no al valor del elemento min/max. Debe eliminar la referencia del iterador para obtener el valor y asignarlo a un doble. Eso es:

cLower = *min_element(C.begin(), C.end());

¿Ha sido útil esta solución?