- Algoritmos de Secuencia No Modificadores
Estas funciones operan sobre los elementos de un contenedor sin alterar su estado ni su orden original.
1.1. Búsqueda de elementos (find)
find(inicio, fin, valor): Localiza el primer elemento equivalente avalor. Devuelve un iterador al final si no hay coincidencias.find_if(inicio, fin, predicado): Busca el primer elemento que cumpla con la condición del predicado.find_end(inicio, fin, sub_inicio, sub_fin): Encuentra la última aparición de una subsecuencia específica.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> data_set = {10, 25, 42, 55, 70};
// Buscar el valor 42
auto iter = std::find(data_set.begin(), data_set.end(), 42);
if (iter != data_set.end()) {
std::cout << "Elemento localizado: " << *iter << '\n';
}
// Localizar el primer valor superior a 50
auto iter_cond = std::find_if(data_set.begin(), data_set.end(), [](int val) {
return val > 50;
});
std::cout << "Primer valor > 50: " << *iter_cond << '\n';
// Búsqueda de subsecuencia
std::vector<int> target_sub = {25, 42};
auto iter_sub = std::find_end(data_set.begin(), data_set.end(), target_sub.begin(), target_sub.end());
if (iter_sub != data_set.end()) {
std::cout << "Subsecuencia inicia en el índice: " << std::distance(data_set.begin(), iter_sub) << '\n';
}
return 0;
}
1.2. Conteo de elementos (count)
count(inicio, fin, valor): Determina la cantidad de elementos idénticos avalor.count_if(inicio, fin, predicado): Calcula cuántos elementos satisfacen el predicado proporcionado.
std::vector<int> measurements = {4, 7, 7, 2, 9, 7, 3};
int total_sevens = std::count(measurements.begin(), measurements.end(), 7);
int odd_count = std::count_if(measurements.begin(), measurements.end(), [](int num) {
return num % 2 != 0;
});
1.3. Iteración y aplicación (for_each)
Ejecuta una función dada sobre cada elemento dentro del intervalo especificado.
std::vector<int> readings = {2, 4, 6, 8, 10};
std::for_each(readings.begin(), readings.end(), [](int& val) {
val += 5;
});
// readings ahora contiene {7, 9, 11, 13, 15}
1.4. Comparación de rangos (equal y mismatch)
equal(ini1, fin1, ini2): Verifica si dos intervalos contienen los mismos elementos en el mismo orden.mismatch(ini1, fin1, ini2): Identifica el primer par de elementos que difieren entre dos rangos.
std::vector<int> seq_a = {10, 20, 30};
std::vector<int> seq_b = {10, 20, 99};
std::vector<int> seq_c = {10, 20, 30, 40};
bool are_equal = std::equal(seq_a.begin(), seq_a.end(), seq_b.begin());
auto diff_pair = std::mismatch(seq_a.begin(), seq_a.end(), seq_c.begin());
if (diff_pair.first != seq_a.end()) {
std::cout << "Diferencia hallada: " << *diff_pair.first << " contra " << *diff_pair.second << '\n';
}
1.5. Evaluación de condiciones globales (all_of, any_of, none_of)
Permiten validar si todos, alguno o ningún elemento del rango cumple con un criterio.
std::vector<int> scores = {85, 90, 92, 88};
bool all_passing = std::all_of(scores.begin(), scores.end(), [](int s) { return s >= 60; });
bool has_perfect = std::any_of(scores.begin(), scores.end(), [](int s) { return s == 100; });
bool no_failures = std::none_of(scores.begin(), scores.end(), [](int s) { return s < 60; });
- Algoritmos de Secuencia Modificadores
Estas herramientas alteran el contenido o la disposición de los elementos en los contenedores.
2.1. Copia de datos (copy y copy_if)
copy(ini, fin, destino): Duplica los elementos del rango origen hacia la posición de destino.copy_if(ini, fin, destino, predicado): Transfiere únicamente los elementos que evalúan como verdaderos en el predicado.
std::vector<int> source_data = {11, 22, 33, 44, 55};
std::vector<int> target_data(5);
std::copy(source_data.begin(), source_data.end(), target_data.begin());
std::vector<int> filtered_data;
std::copy_if(source_data.begin(), source_data.end(), std::back_inserter(filtered_data), [](int x) {
return x > 30;
});
Nota: El uso de std::back_inserter es crucial cuando el contenedor de destino no tiene espacio preasignado, ya que invoca push_back dinámicamente.
2.2. Transformación de elemantos (transform)
Aplica una operación a cada elemento y almacena el resultado en un rango de salida.
std::vector<int> base_vals = {2, 3, 4};
std::vector<int> cubed_vals(3);
std::transform(base_vals.begin(), base_vals.end(), cubed_vals.begin(), [](int v) {
return v * v * v;
});
std::vector<int> weights = {10, 20, 30};
std::vector<int> multipliers = {2, 3, 4};
std::vector<int> results(3);
std::transform(weights.begin(), weights.end(), multipliers.begin(), results.begin(), [](int w, int m) {
return w * m;
});
2.3. Reemplazo de valores (replace)
replace: Sustituye un valor específico por otro nuevo.replace_if: Cambia los elementos que cumplen una condición.replace_copy: Genera una copia con los reemplazos aplicados, dejando el original intacto.
std::vector<int> codes = {1, 2, 3, 2, 5};
std::replace(codes.begin(), codes.end(), 2, 200);
std::replace_if(codes.begin(), codes.end(), [](int c) {
return c > 100;
}, 0);
std::vector<int> modified_codes;
std::replace_copy(codes.begin(), codes.end(), std::back_inserter(modified_codes), 3, 300);
2.4. Eliminación lógica (remove y erase)
Las funciones remove y remove_if no reducen el tamaño del contenedor; simplemente desplazan los elementos no eliminados al principio y devuelven un nuevo iterador final lógico. Para redimensionar, se debe invocar erase.
std::vector<int> items = {10, 20, 30, 20, 40};
auto logical_end = std::remove(items.begin(), items.end(), 20);
items.erase(logical_end, items.end());
items = {1, 2, 3, 4, 5, 6};
items.erase(std::remove_if(items.begin(), items.end(), [](int i) {
return i % 2 != 0;
}), items.end());
2.5. Eliminación de duplicados consecutivos (unique)
Compacta el rango eliminando elementos adyacentes repetidos. Requiere erase para ajustar el tamaño.
std::vector<int> raw_stream = {5, 5, 8, 8, 8, 9, 12, 12};
auto new_boundary = std::unique(raw_stream.begin(), raw_stream.end());
raw_stream.erase(new_boundary, raw_stream.end());
2.6. Inversión y Rotación (reverse y rotate)
std::vector<int> timeline = {1, 2, 3, 4, 5};
std::reverse(timeline.begin(), timeline.end());
std::vector<int> cycle = {10, 20, 30, 40, 50};
std::rotate(cycle.begin(), cycle.begin() + 3, cycle.end());
2.7. Mezcla aleatoria (shuffle)
Reorganiza los elementos de forma pseudoaleatoria utilizando un generador de números aleatorios.
#include <random>
std::vector<int> deck = {1, 2, 3, 4, 5, 6};
std::random_device entropy_source;
std::mt19937 rng_engine(entropy_source());
std::shuffle(deck.begin(), deck.end(), rng_engine);
- Algoritmos de Ordenación y Búsqueda
3.1. Ordenamiento (sort, stable_sort, partial_sort)
sort: Ordenamiento rápido e inestable (Introsort).stable_sort: Mantiene el orden relativo de elementos equivalentes.partial_sort: Ordena solo una porción inicial del contenedor.
std::vector<int> unsorted = {45, 12, 89, 33, 7};
std::sort(unsorted.begin(), unsorted.end());
std::sort(unsorted.begin(), unsorted.end(), std::greater<int>());
struct Record { int id; int priority; };
std::vector<Record> records = {{1, 5}, {2, 5}, {3, 2}};
std::stable_sort(records.begin(), records.end(), [](const Record& a, const Record& b) {
return a.priority < b.priority;
});
std::vector<int> large_set = {99, 14, 52, 3, 28, 71};
std::partial_sort(large_set.begin(), large_set.begin() + 3, large_set.end());
3.2. Selección de enésimo elemento (nth_element)
Reordena el contenedor de modo que el elemento en la posición N sea el que estaría allí si el rango estuviera completamente ordenado.
std::vector<int> metrics = {15, 42, 8, 23, 99, 4};
std::nth_element(metrics.begin(), metrics.begin() + 2, metrics.end());
// metrics[2] ahora contiene el tercer valor más pequeño (15)
3.3. Búsqueda binaria (binary_search, lower_bound, upper_bound)
Estos algoritmos exigen que el rango de entrada esté previamente ordenado.
std::vector<int> sorted_data = {10, 20, 20, 30, 50};
bool is_present = std::binary_search(sorted_data.begin(), sorted_data.end(), 20);
auto lower_it = std::lower_bound(sorted_data.begin(), sorted_data.end(), 20);
auto upper_it = std::upper_bound(sorted_data.begin(), sorted_data.end(), 20);
3.4. Fusión de rangos (merge)
Combina dos secuencias ordenadas en una sola, preservando el orden.
std::vector<int> group_alpha = {2, 4, 6};
std::vector<int> group_beta = {1, 3, 5};
std::vector<int> combined(group_alpha.size() + group_beta.size());
std::merge(group_alpha.begin(), group_alpha.end(), group_beta.begin(), group_beta.end(), combined.begin());
- Operaciones con Montículos (Heaps)
La STL permite tratar rangos contiguos como estructuras de montículo (heap).
std::vector<int> heap_data = {30, 10, 50, 20, 40};
std::make_heap(heap_data.begin(), heap_data.end());
heap_data.push_back(60);
std::push_heap(heap_data.begin(), heap_data.end());
std::pop_heap(heap_data.begin(), heap_data.end());
int top_element = heap_data.back();
heap_data.pop_back();
std::sort_heap(heap_data.begin(), heap_data.end());
- Algoritmos de Mínimos y Máximos
5.1. Comparaciones directas (min y max)
int lowest = std::min(15, 8);
int highest = std::max(15, 8);
auto min_val = std::min({100, 25, 50, 12});
5.2. Búsqueda en rangos (min_element, max_element, minmax_element)
std::vector<int> temperatures = {22, 18, 35, 29, 15};
auto coldest = std::min_element(temperatures.begin(), temperatures.end());
auto hottest = std::max_element(temperatures.begin(), temperatures.end());
auto extremes = std::minmax_element(temperatures.begin(), temperatures.end());
// extremes.first apunta a 15, extremes.second apunta a 35
- Algoritmos Numéricos (<numeric>)
6.1. Acumulación y producto interno
#include <numeric>
std::vector<int> values = {1, 2, 3, 4, 5};
int total_sum = std::accumulate(values.begin(), values.end(), 0);
int total_product = std::accumulate(values.begin(), values.end(), 1, std::multiplies<int>());
std::vector<int> vector_a = {1, 2, 3};
std::vector<int> vector_b = {10, 20, 30};
int dot_product = std::inner_product(vector_a.begin(), vector_a.end(), vector_b.begin(), 0);
6.2. Generación de secuencias y sumas parciales
std::vector<int> sequence(5);
std::iota(sequence.begin(), sequence.end(), 100);
std::vector<int> inputs = {2, 4, 6, 8};
std::vector<int> prefix_sums(inputs.size());
std::partial_sum(inputs.begin(), inputs.end(), prefix_sums.begin());
std::vector<int> diffs(inputs.size());
std::adjacent_difference(inputs.begin(), inputs.end(), diffs.begin());
- Algoritmos de Generación y Conjuntos
7.1. Generación de valores (generate)
std::vector<int> generated(5);
int counter = 100;
std::generate(generated.begin(), generated.end(), [&counter]() {
return counter -= 10;
});
std::generate_n(generated.begin(), 3, [&counter]() {
return counter += 5;
});
7.2. Operaciones de conjuntos
Estas funciones requeiren que los rangos de entrada estén ordenados.
std::vector<int> set_one = {1, 3, 5, 7, 9};
std::vector<int> set_two = {3, 5, 7, 11, 13};
std::vector<int> output;
bool is_subset = std::includes(set_one.begin(), set_one.end(), set_two.begin(), set_two.begin() + 3);
std::set_union(set_one.begin(), set_one.end(), set_two.begin(), set_two.end(), std::back_inserter(output));
output.clear();
std::set_intersection(set_one.begin(), set_one.end(), set_two.begin(), set_two.end(), std::back_inserter(output));
output.clear();
std::set_difference(set_one.begin(), set_one.end(), set_two.begin(), set_two.end(), std::back_inserter(output));
output.clear();
std::set_symmetric_difference(set_one.begin(), set_one.end(), set_two.begin(), set_two.end(), std::back_inserter(output));
- Preguntas Frecuentes y Consideraciones Técnicas
- ¿Cuándo elegir
stable_sortsobresort?
Utilicestable_sortcuando el orden relativo original de los elementos con claves equivalentes deba preservarse (por ejemplo, al ordenar por una columna secundaria). Tenga en cuenta questable_sortpuede requerir memoria adicional O(N), mientras quesortopera in-place. - ¿Por qué
std::removeno elimina elementos físicamente?
Los algoritmos de la STL operan mediente iteradores y no tienen conocimiento directo del contenedor subyacente. Por lo tanto,removesolo puede reorganizar los elementos y devolver un nuevo límite lógico. La eliminación física de la memoria es responsabilidad del contenedor a través de su métodoerase. - ¿Qué algoritmos exigen rangos preordenados?
Cualquier algoritmo basado en búsqueda binaria (binary_search,lower_bound,upper_bound,equal_range), así como las operaciones de conjuntos (set_union,set_intersection, etc.) ymerge, requieren estrictamente que los datos de entrada estén ordenados para garantizar un comportamiento correcto y una complejidad temporal óptima.