Algoritmos de la STL de C++: Guía Completa con Ejemplos

Estos algoritmos no alteran los elementos del contenedor sobre el que operan.

1.1 find y find_if
  • find(inicio, fin, valor): devuelve un iterador al primer elemento igual a valor (o fin si no se encuentra).
  • find_if(inicio, fin, predicado): devuelve el iterador al primer elemento que cumple el predicado.
  • find_end(inicio, fin, sub_inicio, sub_fin): busca la última aparición de una subsecuencia.
std::vector<int> datos = {1, 3, 5, 7, 9};

// Buscar el valor 5
auto iter = std::find(datos.begin(), datos.end(), 5);
if (iter != datos.end()) {
    std::cout << "Encontrado: " << *iter << '\n';  // 5
}

// Primer elemento mayor que 6
auto iter2 = std::find_if(datos.begin(), datos.end(), [](int x) {
    return x > 6;
});
std::cout << "Primero >6: " << *iter2 << '\n';  // 7

// Buscar subsecuencia {3,5}
std::vector<int> sub = {3, 5};
auto iter3 = std::find_end(datos.begin(), datos.end(), sub.begin(), sub.end());
if (iter3 != datos.end()) {
    std::cout << "Subsecuencia comienza en índice: " << (iter3 - datos.begin()) << '\n';  // 1
}

1.2 count y count_if
  • count(inicio, fin, valor): cuenta cuántas veces aparece valor.
  • count_if(inicio, fin, predicado): cuenta los elementos que cumplen el predicado.
std::vector<int> numeros = {1, 2, 3, 2, 4, 2};
int veces = std::count(numeros.begin(), numeros.end(), 2);        // 3
int pares = std::count_if(numeros.begin(), numeros.end(),
                           [](int x) { return x % 2 == 0; });    // 4

1.3 for_each

Aplica una función a cada elemento del rango.

std::vector<int> valores = {1, 2, 3, 4, 5};
std::for_each(valores.begin(), valores.end(), [](int& x) {
    x *= 2;  // Duplica cada elemento
});
// valores: {2, 4, 6, 8, 10}

1.4 equal y mismatch
  • equal(inicio1, fin1, inicio2): determina si dos rangos son iguales.
  • mismatch(inicio1, fin1, inicio2): devuelve un par de iteradores al primer elemento que difiere.
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {1, 2, 4};
std::vector<int> c = {1, 2, 3, 4};

bool iguales = std::equal(a.begin(), a.end(), b.begin());
std::cout << "a == b? " << std::boolalpha << iguales << '\n';  // false

auto par = std::mismatch(a.begin(), a.end(), c.begin());
if (par.first != a.end()) {
    std::cout << "Diferencia: " << *par.first << " vs " << *par.second << '\n';
}

1.5 all_of, any_of, none_of

Verifican si todos, alguno o ninguno de los elementos cumplen una condición.

std::vector<int> lista = {2, 4, 6, 8};
bool todos_pares = std::all_of(lista.begin(), lista.end(),
                               [](int x) { return x % 2 == 0; }); // true
bool algun_impar = std::any_of(lista.begin(), lista.end(),
                               [](int x) { return x % 2 != 0; }); // false
bool ningun_neg = std::none_of(lista.begin(), lista.end(),
                               [](int x) { return x < 0; });     // true

2. Algoritmos de modificación

Estos algoritmos modifican los elementos del contenedor.

2.1 copy y copy_if
  • copy(inicio, fin, destino): copia los elementos a un destino.
  • copy_if(inicio, fin, destino, predicado): copia solo los que cumplen el predicado.
std::vector<int> fuente = {1, 2, 3, 4, 5};
std::vector<int> destino(5);
std::copy(fuente.begin(), fuente.end(), destino.begin()); // destino: {1,2,3,4,5}

std::vector<int> pares;
std::copy_if(fuente.begin(), fuente.end(), std::back_inserter(pares),
             [](int x) { return x % 2 == 0; }); // pares: {2,4}

2.2 transform

Aplica una función a cada elemento y guarda el resultado en otro rango.

std::vector<int> nums = {1, 2, 3};
std::vector<int> cuadrados(3);
std::transform(nums.begin(), nums.end(), cuadrados.begin(),
               [](int x) { return x * x; }); // cuadrados: {1,4,9}

std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {4, 5, 6};
std::vector<int> suma(3);
std::transform(v1.begin(), v1.end(), v2.begin(), suma.begin(),
               [](int a, int b) { return a + b; }); // suma: {5,7,9}

2.3 replace, replace_if y replace_copy
  • replace(inicio, fin, viejo, nuevo): reemplaza viejo por nuevo.
  • replace_if(inicio, fin, predicado, nuevo): reemplaza los que cumplen el predicado.
  • replace_copy(inicio, fin, destino, viejo, nuevo): copia reemplazando (no modifica el original).
std::vector<int> vals = {1, 2, 3, 2, 5};
std::replace(vals.begin(), vals.end(), 2, 20); // vals: {1,20,3,20,5}

std::replace_if(vals.begin(), vals.end(),
                [](int x) { return x > 10; }, 0); // vals: {1,0,3,0,5}

std::vector<int> copia;
std::replace_copy(vals.begin(), vals.end(), std::back_inserter(copia), 3, 300);
// copia: {1,0,300,0,5}

2.4 remove, remove_if y erase
  • remove(inicio, fin, valor): mueve los iguales a valor al final, devuelve nuevo final lógico.
  • remove_if(inicio, fin, predicado): similar pero con predicado.
std::vector<int> datos = {1, 2, 3, 2, 4};
auto nuevo_fin = std::remove(datos.begin(), datos.end(), 2); // lógico: {1,3,4,2,2}
datos.erase(nuevo_fin, datos.end()); // físico: {1,3,4}

// Eliminar pares con lambda
datos = {1, 2, 3, 4, 5};
datos.erase(std::remove_if(datos.begin(), datos.end(),
                           [](int x) { return x % 2 == 0; }),
            datos.end()); // datos: {1,3,5}

2.5 unique

Elimina duplicados consecutivos, devuelve nuevo final lógico. Normalmente se usa con erase.

std::vector<int> v = {1, 1, 2, 2, 3, 3, 3, 4, 5};
auto fin_unico = std::unique(v.begin(), v.end());
v.erase(fin_unico, v.end()); // v: {1,2,3,4,5}

2.6 reverse
std::vector<int> v = {1, 2, 3, 4, 5};
std::reverse(v.begin(), v.end()); // v: {5,4,3,2,1}

2.7 rotate
std::vector<int> v = {1, 2, 3, 4, 5};
std::rotate(v.begin(), v.begin() + 2, v.end()); // v: {3,4,5,1,2}

2.8 shuffle
#include <random>
#include <algorithm>

std::vector<int> v = {1, 2, 3, 4, 5};
std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(v.begin(), v.end(), gen); // orden aleatorio

3. Allgoritmos de ordenación

3.1 sort, stable_sort y partial_sort
std::vector<int> v = {5, 3, 1, 4, 2};
std::sort(v.begin(), v.end()); // {1,2,3,4,5}
std::sort(v.begin(), v.end(), std::greater<int>()); // {5,4,3,2,1}
std::sort(v.begin(), v.end(), [](int a, int b) { return a < b; }); // personalizado

std::vector<std::pair<int,int>> vp = {{1, 2}, {2, 1}, {1, 1}, {2, 2}};
std::stable_sort(vp.begin(), vp.end(),
                 [](const auto& a, const auto& b) { return a.first < b.first; });

std::vector<int> v2 = {5, 3, 1, 4, 2, 6};
std::partial_sort(v2.begin(), v2.begin() + 3, v2.end());
// v2 primeros tres: {1,2,3}

3.2 nth_element
std::vector<int> v = {5, 3, 1, 4, 2, 6};
std::nth_element(v.begin(), v.begin() + 2, v.end()); // v[2] = 3 (tercer menor)

3.3 binary_search, lower_bound, upper_bound

Requieren contenedor ordenado.

std::vector<int> ord = {1, 3, 3, 5, 7};

bool existe = std::binary_search(ord.begin(), ord.end(), 3); // true
auto lb = std::lower_bound(ord.begin(), ord.end(), 3);
auto ub = std::upper_bound(ord.begin(), ord.end(), 3);
std::cout << "lower: " << (lb - ord.begin()) << '\n'; // 1
std::cout << "upper: " << (ub - ord.begin()) << '\n'; // 3

3.4 merge

Fusiona dos rangos ordenados.

std::vector<int> a = {1, 3, 5};
std::vector<int> b = {2, 4, 6};
std::vector<int> fusion(a.size() + b.size());
std::merge(a.begin(), a.end(), b.begin(), b.end(), fusion.begin());
// fusion: {1,2,3,4,5,6}

4. Algoritmos de montículo (heap)

std::vector<int> v = {4, 1, 3, 2, 5};
std::make_heap(v.begin(), v.end()); // {5,4,3,2,1}

v.push_back(6);
std::push_heap(v.begin(), v.end()); // {6,4,5,2,1,3}

std::pop_heap(v.begin(), v.end()); // mueve el máximo al final
int max = v.back(); // 6
v.pop_back();

std::sort_heap(v.begin(), v.end()); // {1,2,3,4,5}

5. Algoritmos de mínimo/máximo

5.1 min y max
int a = 5, b = 3;
int min = std::min(a, b); // 3
int max = std::max(a, b); // 5
auto min_lista = std::min({4, 2, 8, 5, 1}); // 1
auto max_lista = std::max({4, 2, 8, 5, 1}); // 8

5.2 min_element y max_element
std::vector<int> v = {3, 1, 4, 2, 5};
auto it_min = std::min_element(v.begin(), v.end()); // apunta a 1
auto it_max = std::max_element(v.begin(), v.end()); // apunta a 5

5.3 minmax_element (C++11)
auto minmax = std::minmax_element(v.begin(), v.end());
// minmax.first apunta a 1, minmax.second apunta a 5

6. Algoritmos numéricos (<numeric>)

6.1 accumulate
#include <numeric>

std::vector<int> v = {1, 2, 3, 4, 5};
int suma = std::accumulate(v.begin(), v.end(), 0); // 15
int producto = std::accumulate(v.begin(), v.end(), 1,
                               std::multiplies<int>()); // 120

6.2 inner_product
std::vector<int> a = {1, 2, 3};
std::vector<int> b = {4, 5, 6};
int producto_escalar = std::inner_product(a.begin(), a.end(),
                                          b.begin(), 0); // 32

6.3 iota
std::vector<int> v(5);
std::iota(v.begin(), v.end(), 10); // {10,11,12,13,14}

6.4 partial_sum
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst(src.size());
std::partial_sum(src.begin(), src.end(), dst.begin()); // {1,3,6,10,15}

6.5 adjacent_difference
std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dst(src.size());
std::adjacent_difference(src.begin(), src.end(), dst.begin()); // {1,1,1,1,1}

7. Otros algoritmos

7.1 generate
std::vector<int> v(5);
int n = 0;
std::generate(v.begin(), v.end(), [&n]() { return n++; }); // {0,1,2,3,4}

7.2 generate_n
std::vector<int> v(5);
int m = 10;
std::generate_n(v.begin(), 3, [&m]() { return m++; }); // primeros tres: {10,11,12}

7.3 includes
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {2, 4};
bool contiene = std::includes(v1.begin(), v1.end(),
                              v2.begin(), v2.end()); // true

7.4 set_union, set_intersection, set_difference, set_symmetric_difference
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {3, 4, 5, 6, 7};
std::vector<int> res;

std::set_union(v1.begin(), v1.end(), v2.begin(), v2.end(),
               std::back_inserter(res)); // {1,2,3,4,5,6,7}
res.clear();

std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(),
                      std::back_inserter(res)); // {3,4,5}
res.clear();

std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
                    std::back_inserter(res)); // {1,2}
res.clear();

std::set_symmetric_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
                              std::back_inserter(res)); // {1,2,6,7}

8. Preguntas frecuentes

  1. ¿Diferencia entre sort y stable_sort?
    sort usa introsort (inestable), O(n log n). stable_sort usa mergesort (estable), O(n log n) pero consume más memoria.
  2. ¿Por qué remove requiere erase?
    remove solo mueve elementos a eliminar al final y devuelve un iterador lógico; erase libera la memoria. Se usa la expresión cont.erase(remove(...), cont.end()).
  3. ¿Qué algoritmos requieren contenedor ordenado?
    Búsqueda binaria (binary_search, lower_bound, upper_bound), algoritmos de conjunto (set_intersection, set_union, etc.) y merge.

Etiquetas: C++ STL algorithms sort find

Publicado el 6-24 18:47