Estas rotinas examinam os dados sem alterar o estado original dos contêineres.
1.1. Localização de Elementos
As funções de busca permitem encontrar itens específicos ou que atendam a certas condições.
std::find: Localiza a primeira ocorrência de um valor exato.std::find_if: Localiza o primeiro elemento que satisfaça uma condição (função booleana).std::find_end: Identifica a última ocorrência de uma subsequência.
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> pontuacoes = {10, 25, 30, 45, 50};
// Buscar um valor exato
auto alvo = std::find(pontuacoes.begin(), pontuacoes.end(), 30);
if (alvo != pontuacoes.end()) {
std::cout << "Valor exato encontrado: " << *alvo << "\n";
}
// Buscar com condição
auto maior_que_40 = std::find_if(pontuacoes.begin(), pontuacoes.end(), [](int p) {
return p > 40;
});
std::cout << "Primeiro valor > 40: " << *maior_que_40 << "\n";
// Buscar subsequência
std::vector<int> subseq = {25, 30};
auto fim_subseq = std::find_end(pontuacoes.begin(), pontuacoes.end(), subseq.begin(), subseq.end());
if (fim_subseq != pontuacoes.end()) {
std::cout << "Índice da subsequência: " << std::distance(pontuacoes.begin(), fim_subseq) << "\n";
}
return 0;
}
1.2. Contagem e Validação
Permitem quantificar elementos ou verificar propriedades lógicas sobre o intervalo.
std::countestd::count_if: Contam ocorrências de um valor ou de elementos que passem em um teste.std::all_of,std::any_of,std::none_of: Verificam se todos, algum ou nenhum elemento atende a um predicado.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> idades = {20, 22, 19, 25, 21};
int maiores_de_20 = std::count_if(idades.begin(), idades.end(), [](int i) { return i > 20; });
std::cout << "Pessoas com mais de 20 anos: " << maiores_de_20 << "\n";
bool todos_maiores_de_idade = std::all_of(idades.begin(), idades.end(), [](int i) { return i >= 18; });
std::cout << "Todos maiores de idade? " << (todos_maiores_de_idade ? "Sim" : "Nao") << "\n";
bool algum_idoso = std::any_of(idades.begin(), idades.end(), [](int i) { return i > 60; });
std::cout << "Há alguém com mais de 60? " << (algum_idoso ? "Sim" : "Nao") << "\n";
return 0;
}
1.3. Comparação de Intervalos
Utilizadas para verificar igualdade ou encontrar divergências entre duas sequências.
std::equal: Compara se dois intervalos possuem os mesmos elementos.std::mismatch: Retorna um par de iteradores apontando para o primeiro elemento diferente.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<char> senha1 = {'a', 'b', 'c', 'd'};
std::vector<char> senha2 = {'a', 'b', 'x', 'd'};
bool iguais = std::equal(senha1.begin(), senha1.end(), senha2.begin());
std::cout << "Senhas iguais? " << std::boolalpha << iguais << "\n";
auto diff = std::mismatch(senha1.begin(), senha1.end(), senha2.begin());
if (diff.first != senha1.end()) {
std::cout << "Divergência: '" << *diff.first << "' vs '" << *diff.second << "'\n";
}
return 0;
}
- Operações de Mutação de Sequências
Estas funções alteram o conteúdo ou a ordem dos elementos nos contêineres de origem ou destino.
2.1. Cópia e Transformação
Perimtem transferir dados e aplicar operações matemáticas ou lógicas durante o processo.
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
int main() {
std::vector<double> precos = {10.5, 20.0, 15.75, 30.2};
std::vector<double> precos_com_desconto;
// Copiar apenas valores maiores que 15
std::copy_if(precos.begin(), precos.end(), std::back_inserter(precos_com_desconto),
[](double p) { return p > 15.0; });
// Transformar aplicando um desconto de 10%
std::vector<double> precos_finais(precos_com_desconto.size());
std::transform(precos_com_desconto.begin(), precos_com_desconto.end(), precos_finais.begin(),
[](double p) { return p * 0.9; });
for(double p : precos_finais) std::cout << p << " ";
return 0;
}
2.2. Substituição e Remoção
Alteram valores específicos ou removem elementos com base em critérios.
#include <vector>
#include <algorithm>
int main() {
std::vector<int> registros = {1, 2, 0, 4, 0, 5};
// Substituir 0 por -1
std::replace(registros.begin(), registros.end(), 0, -1);
// Remover valores negativos (lógica de remoção)
auto novo_fim = std::remove_if(registros.begin(), registros.end(), [](int r) { return r < 0; });
registros.erase(novo_fim, registros.end()); // Remoção física (Erase-Remove Idiom)
// Remover duplicatas consecutivas
std::vector<int> dados = {1, 1, 2, 2, 2, 3};
auto ultimo = std::unique(dados.begin(), dados.end());
dados.erase(ultimo, dados.end());
return 0;
}
2.3. Reorganização
Alteram a disposição dos elementos sem necessariamente mudar seus valores.
#include <vector>
#include <algorithm>
#include <random>
int main() {
std::vector<int> fila = {1, 2, 3, 4, 5};
// Inverter a ordem
std::reverse(fila.begin(), fila.end());
// Rotacionar para que o terceiro elemento seja o primeiro
std::rotate(fila.begin(), fila.begin() + 2, fila.end());
// Embaralhar aleatoriamente
std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(fila.begin(), fila.end(), gen);
return 0;
}
- Ordenação e Busca em Dados Ordenados
3.1. Algoritmos de Ordenação
Organizam os elementos com base em critérios de comparação.
std::sort: Ordenação rápida (não estável).std::stable_sort: Mantém a ordem relativa de elementos equivalentes.std::partial_sort: Ordena apenas os primeiros N elementos.std::nth_element: Posiciona o N-ésimo elemanto corretamente, particionando o restante.
#include <vector>
#include <algorithm>
#include <string>
struct Produto {
std::string nome;
float preco;
};
int main() {
std::vector<Produto> catalogo = {
{"Teclado", 150.0f}, {"Mouse", 50.0f}, {"Monitor", 800.0f}, {"Webcam", 120.0f}
};
// Ordenar por preço (crescente)
std::sort(catalogo.begin(), catalogo.end(), [](const Produto& a, const Produto& b) {
return a.preco < b.preco;
});
// Ordenação estável por nome
std::stable_sort(catalogo.begin(), catalogo.end(), [](const Produto& a, const Produto& b) {
return a.nome < b.nome;
});
// Colocar os 2 mais baratos no início
std::partial_sort(catalogo.begin(), catalogo.begin() + 2, catalogo.end(), [](const Produto& a, const Produto& b) {
return a.preco < b.preco;
});
return 0;
}
3.2. Busca Binária e Fusão
Exigem que o contêiner esteja previamente ordenado.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> ids_ordenados = {10, 20, 30, 40, 50};
bool existe = std::binary_search(ids_ordenados.begin(), ids_ordenados.end(), 30);
auto limite_inf = std::lower_bound(ids_ordenados.begin(), ids_ordenados.end(), 25);
auto limite_sup = std::upper_bound(ids_ordenados.begin(), ids_ordenados.end(), 30);
std::vector<int> lista_a = {1, 3, 5};
std::vector<int> lista_b = {2, 4, 6};
std::vector<int> combinada(lista_a.size() + lista_b.size());
std::merge(lista_a.begin(), lista_a.end(), lista_b.begin(), lista_b.end(), combinada.begin());
return 0;
}
- Estruturas de Heap e Extremos
4.1. Manipulação de Heaps
Transformam um contêiner em uma estrutura de heap (árvore binária completa), útil para filas de prioridade.
#include <vector>
#include <algorithm>
int main() {
std::vector<int> tarefas = {3, 1, 4, 1, 5, 9};
std::make_heap(tarefas.begin(), tarefas.end()); // Cria um max-heap
tarefas.push_back(10);
std::push_heap(tarefas.begin(), tarefas.end()); // Adiciona e reorganiza
std::pop_heap(tarefas.begin(), tarefas.end()); // Move o maior para o final
tarefas.pop_back(); // Remove o maior
std::sort_heap(tarefas.begin(), tarefas.end()); // Ordena o heap
return 0;
}
4.2. Encontrar Mínimos e Máximos
Localizam os valores extremos em um intervalo.
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> temperaturas = {15, 22, 9, 30, 12};
auto minima = std::min_element(temperaturas.begin(), temperaturas.end());
auto maxima = std::max_element(temperaturas.begin(), temperaturas.end());
auto extremos = std::minmax_element(temperaturas.begin(), temperaturas.end());
std::cout << "Min: " << *extremos.first << ", Max: " << *extremos.second << "\n";
return 0;
}
- Operações Numéricas e Conjuntos
Localizadas no cabeçalho <numeric> e algoritmos de teoria dos conjuntos.
5.1. Cálculos e Preenchimento
#include <vector>
#include <numeric>
#include <iostream>
int main() {
std::vector<int> valores = {1, 2, 3, 4, 5};
// Soma acumulada
int total = std::accumulate(valores.begin(), valores.end(), 0);
// Produto acumulado
int produto = std::accumulate(valores.begin(), valores.end(), 1, std::multiplies<int>());
// Preencher com sequência
std::vector<int> sequencia(5);
std::iota(sequencia.begin(), sequencia.end(), 100); // 100, 101, 102...
// Somas parciais
std::vector<int> somas_parciais(5);
std::partial_sum(valores.begin(), valores.end(), somas_parciais.begin());
// Diferenças adjacentes
std::vector<int> diffs(5);
std::adjacent_difference(valores.begin(), valores.end(), diffs.begin());
return 0;
}
5.2. Operações de Conjuntos
Requerem intervalos ordenados para realizar união, interseção e diferença.
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> conjunto_a = {1, 2, 3, 4, 5};
std::vector<int> conjunto_b = {4, 5, 6, 7, 8};
std::vector<int> resultado;
std::set_union(conjunto_a.begin(), conjunto_a.end(),
conjunto_b.begin(), conjunto_b.end(),
std::back_inserter(resultado));
resultado.clear();
std::set_intersection(conjunto_a.begin(), conjunto_a.end(),
conjunto_b.begin(), conjunto_b.end(),
std::back_inserter(resultado));
resultado.clear();
std::set_difference(conjunto_a.begin(), conjunto_a.end(),
conjunto_b.begin(), conjunto_b.end(),
std::back_inserter(resultado));
return 0;
}
- Perguntas Frequantes
Qual a diferença entre std::sort e std::stable_sort?
O std::sort utiliza uma variante do QuickSort (Introsort) e não garante a preservação da ordem relativa de elementos com chaves iguais. O std::stable_sort baseia-se no MergeSort, garantindo estabilidade, mas geralmente consome mais memória.
Por que o std::remove não diminui o tamanho do contêiner?
O algoritmo std::remove apenas desloca os elementos não removidos para o início do contêiner, retornando um novo iterador de fim lógico. Para alterar o tamanho físico e liberar memória, é obrigatório chamar o método erase do contêiner com o iterador retornado e o fim original (Idioma Erase-Remove).
Quais algoritmos exigem dados ordenados?
Algoritmos de busca binária (binary_search, lower_bound, upper_bound), fusão (merge) e operações de conjuntos (set_union, set_intersection, etc.) dependem da ordenação prévia para funcionar corretamente e manter sua complexidade de tempo otimizada.