Dominando Algoritmos da STL no C++ Moderno

1. Algoritmos de Consulta (Não Modificadores)

Estes algoritmos realizam operações de leitura sobre os containers sem alterar o estado ou a ordem dos elementos originais.

1.1 find e find_if

Utilizados para localizar elementos específicos ou que atendam a um critério lógico (predicado).

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

std::vector<int> dados = {10, 25, 40, 55, 70};

// Busca por valor exato
auto it = std::find(dados.begin(), dados.end(), 40);
if (it != dados.end()) {
    std::cout << "Valor encontrado: " << *it << std::endl;
}

// Busca baseada em condição (primeiro valor par)
auto it_par = std::find_if(dados.begin(), dados.end(), [](int n) {
    return n % 2 == 0;
});
if (it_par != dados.end()) {
    std::cout << "Primeiro par: " << *it_par << std::endl;
}

1.2 count e count_if

Servem para quantificar a ocorrência de elementos no intervalo.

std::vector<int> notas = {7, 5, 8, 7, 9, 7};
// Conta quantas vezes o número 7 aparece
long qtd_sete = std::count(notas.begin(), notas.end(), 7); 

// Conta elementos maiores que 6
long aprovados = std::count_if(notas.begin(), notas.end(), [](int n) {
    return n > 6;
});

1.3 Verificadores Lógicos: all_of, any_of e none_of

Validam propriedades sobre toda a coleção de forma booleana.

std::vector<int> valores = {2, 4, 6, 8};

bool todos_pares = std::all_of(valores.begin(), valores.end(), [](int x) { return x % 2 == 0; });
bool algum_impar = std::any_of(valores.begin(), valores.end(), [](int x) { return x % 2 != 0; });
bool nenhum_negativo = std::none_of(valores.begin(), valores.end(), [](int x) { return x < 0; });

2. Algoritmos de Modificação de Sequência

Estas funções alteram o conteúdo dos containers, seja movendo, copiando ou transformando elementos.

2.1 transform

Aplica uma operação em cada elemento e armazena o resultado em um novo destino (ou no próprio container).

std::vector<int> entrada = {1, 2, 3, 4};
std::vector<int> dobro;

// Multiplica cada elemento por 2 e insere em 'dobro'
std::transform(entrada.begin(), entrada.end(), std::back_inserter(dobro), [](int n) {
    return n * 2;
});

2.2 O Idioma Erase-Remove

O algoritmo std::remove não altera o tamanho do container; ele apenas desloca os elementos indesejados para o final. Para deletá-los fisicamente, deve-se usar o método erase do container.

std::vector<int> lista = {1, 2, 99, 3, 99, 4};

// Remove logicamente o valor 99
auto novo_fim = std::remove(lista.begin(), lista.end(), 99);

// Remove fisicamente do vector
lista.erase(novo_fim, lista.end());
// Resultado: {1, 2, 3, 4}

2.3 replace e replace_if

std::vector<int> seq = {10, 20, 30, 20};
// Substitui 20 por 100
std::replace(seq.begin(), seq.end(), 20, 100); 

// Substitui valores menores que 50 por zero
std::replace_if(seq.begin(), seq.end(), [](int n) { return n < 50; }, 0);

3. Ordenação e Busca Binária

Para alta performance em buscas, a ordenação é um pré-requisito fundamental.

3.1 sort e stable_sort

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

// Ordenação padrão (geralmente Introsort)
std::sort(itens.begin(), itens.end()); 

// Ordenação estável (preserva ordem de elementos iguais)
std::stable_sort(itens.begin(), itens.end(), std::greater<int>()); // Ordem decrescente

3.2 Pesquisa em Coleções Ordenadas

std::vector<int> ordenado = {10, 20, 20, 30, 40};

// Verifica existência (O(log n))
bool existe = std::binary_search(ordenado.begin(), ordenado.end(), 20);

// Encontra o primeiro elemento que não é menor que 20
auto lb = std::lower_bound(ordenado.begin(), ordenado.end(), 20);

// Encontra o primeiro elemento maior que 20
auto ub = std::upper_bound(ordenado.begin(), ordenado.end(), 20);

4. Algoritmos Numéricos

Localizados no header <numeric>, são essenciais para cálculos matemáticos em sequências.

4.1 accumulate e iota

#include <numeric>

std::vector<int> serie(5);
// Preenche com 1, 2, 3, 4, 5
std::iota(serie.begin(), serie.end(), 1);

// Soma total dos elementos
int soma = std::accumulate(serie.begin(), serie.end(), 0);

// Produto total dos elementos
int produto = std::accumulate(serie.begin(), serie.end(), 1, std::multiplies<int>());

5. Manipulação de Heaps e Extremos

A STL permite tratar vetores como estruturas de dados Heap (Max-Heap por padrão).

std::vector<int> v = {3, 1, 4, 1, 5, 9};

std::make_heap(v.begin(), v.end()); // Transforma em heap
std::pop_heap(v.begin(), v.end());  // Move o maior para o fim
int maior = v.back();
v.pop_back();                       // Remove o elemento

// Encontrar extremos sem ordenar
auto [min, max] = std::minmax_element(v.begin(), v.end());
std::cout << "Min: " << *min << " Max: " << *max;

6. Operações de Conjunto

Trabalham com intervalos ordenados para realizar operações matemáticas de conjuntos.

std::vector<int> conjunto1 = {1, 2, 3};
std::vector<int> conjunto2 = {2, 3, 4};
std::vector<int> resultado;

// Interseção: {2, 3}
std::set_intersection(conjunto1.begin(), conjunto1.end(),
                      conjunto2.begin(), conjunto2.end(),
                      std::back_inserter(resultado));

Tags: cpp STL Algoritmos programacao-moderna estrutura-de-dados

Publicado em 7-22 12:30