Algoritmos da Biblioteca Padrão C++: Manipulação de Sequências e Transformações

Inversão e Rotação de Elementos

A biblioteca padrão C++ oferece diversos algoritmos para reorganizar elementos em contêineres. Analisemos três funções essenciais: reverse, reverse_copy e rotate.

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

template<typename Container>
void exibir(const Container& dados);

void demonstrar_inversao();
void demonstrar_rotacao();

int main() {
    std::cout << "=== Demonstração de Inversão ===\n";
    demonstrar_inversao();
    std::cout << "\n=== Demonstração de Rotação ===\n";
    demonstrar_rotacao();
}

template<typename Container>
void exibir(const Container& dados) {
    for(const auto& elemento : dados)
        std::cout << elemento << ' ';
    std::cout << '\n';
}

void demonstrar_inversao() {
    using namespace std;
    
    string original{"abcdefghij"};
    cout << "Original: " << original << endl;
    
    string copia_invertida(original);
    reverse(copia_invertida.begin(), copia_invertida.end());
    cout << "Invertida (in-place): " << copia_invertida << endl;
    
    string destino(original.size(), ' ');
    reverse_copy(original.begin(), original.end(), destino.begin());
    cout << "Cópia invertida: " << destino << endl;
    
    vector<int> numeros{5, 3, 8, 1, 9};
    cout << "Vetor: "; exibir(numeros);
    vector<int> nums_invertidos(numeros.size());
    reverse_copy(numeros.begin(), numeros.end(), nums_invertidos.begin());
    cout << "Cópia: "; exibir(nums_invertidos);
}

void demonstrar_rotacao() {
    using namespace std;
    
    vector<int> sequencia{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    cout << "Sequência: "; exibir(sequencia);
    
    vector<int> rot1(sequencia);
    rotate(rot1.begin(), rot1.begin() + 3, rot1.end());
    cout << "Rotação +3: "; exibir(rot1);
    
    vector<int> rot2(sequencia);
    rotate(rot2.begin(), rot2.end() - 2, rot2.end());
    cout << "Rotação -2: "; exibir(rot2);
}

Diferença entre reverse e reverse_copy:

  • reverse: Modifica o contêiner original, invertindo os elementos em seu próprio espaço de memória
  • reverse_copy: Preserva o contêiner original, copiando os elementos invertidos para um destino separado

Comportamanto de rotate:

A função realiza uma rotação circular onde o elemento apontado pelo segundo parâmetro torna-se o novo primeiro elemento. Os parâmetros são: (inicio, novo_inicio, fim).

Geração e Estatísticas de Dados

Para preenchimento de contêineres e análise estatística, utilizamos generate, minmax_element e accumulate.

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <iomanip>
#include <cstdlib>
#include <ctime>

template<typename T>
void imprimir(const T& colecao);

void analise_completa();

int main() {
    std::srand(static_cast<unsigned>(std::time(nullptr)));
    analise_completa();
}

template<typename T>
void imprimir(const T& colecao) {
    for(const auto& val : colecao)
        std::cout << val << ' ';
    std::cout << '\n';
}

void analise_completa() {
    using namespace std;
    
    vector<int> amostra(12);
    auto gerador = []() { return rand() % 201 - 100; };
    generate(amostra.begin(), amostra.end(), gerador);
    
    cout << "Amostra: "; imprimir(amostra);
    
    auto [menor, maior] = minmax_element(amostra.begin(), amostra.end());
    cout << "Extremos: " << *menor << " e " << *maior << endl;
    
    double media_geral = accumulate(amostra.begin(), amostra.end(), 0.0) / amostra.size();
    cout << "Média: " << fixed << setprecision(2) << media_geral << endl;
    
    sort(amostra.begin(), amostra.end());
    double media_central = accumulate(amostra.begin() + 1, amostra.end() - 1, 0.0) / (amostra.size() - 2);
    cout << "Média sem extremos: " << media_central << endl;
}

Vantagem de minmax_element: Realiza uma única passagem pela coleção, enquanto chamadas separadas de min_element e max_element exigiriam duas travessias completas.

Transformações de Caracteres

O algoritmo transform aplica funções personalizadas a cada elemento de uma sequência.

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

unsigned char cifrar(unsigned char caractere);
void converter_case();
void aplicar_cifra();

int main() {
    converter_case();
    aplicar_cifra();
}

unsigned char cifrar(unsigned char caractere) {
    if(caractere == 'z') return 'a';
    if(caractere == 'Z') return 'A';
    if(isalpha(caractere)) return static_cast<unsigned char>(caractere + 1);
    return caractere;
}

void converter_case() {
    using namespace std;
    string texto{"Programação C++ 2024!"};
    cout << "Original: " << texto << '\n';
    
    string minusculas, maiusculas;
    for(auto c : texto) {
        minusculas += static_cast<char>(tolower(c));
        maiusculas += static_cast<char>(toupper(c));
    }
    cout << "Minúsculas: " << minusculas << '\n';
    cout << "Maiúsculas: " << maiusculas << '\n';
}

void aplicar_cifra() {
    using namespace std;
    string mensagem{"Zebra"};
    cout << "\nMensagem: " << mensagem << '\n';
    
    string cifrada(mensagem.size(), ' ');
    transform(mensagem.begin(), mensagem.end(), cifrada.begin(), cifrar);
    cout << "Cifrada: " << cifrada << '\n';
    
    transform(mensagem.begin(), mensagem.end(), mensagem.begin(), cifrar);
    cout << "Sobrescrita: " << mensagem << '\n';
}

Parâmetros de transform: (primeiro, ultimo, destino, operacao). Quando o destino coincide com a origem, a operação ocorre in-place.

Verificação de Palíndromos

Implementação de verificação com e sem sensibilidade a maiúsculas/minúsculas.

#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>

bool palindromo_estrito(const std::string& entrada);
bool palindromo_flexivel(const std::string& entrada);

int main() {
    using namespace std;
    string linha;
    
    cout << "Digite palavras (Ctrl+Z para encerrar):\n";
    while(getline(cin, linha)) {
        cout << boolalpha 
             << "Estrito: " << palindromo_estrito(linha) << "\n"
             << "Flexível: " << palindromo_flexivel(linha) << "\n\n";
    }
}

bool palindromo_estrito(const std::string& entrada) {
    auto meio = entrada.size() / 2;
    for(size_t i = 0; i < meio; ++i)
        if(entrada[i] != entrada[entrada.size() - 1 - i])
            return false;
    return true;
}

bool palindromo_flexivel(const std::string& entrada) {
    std::string normalizada;
    for(auto c : entrada)
        normalizada += static_cast<char>(toupper(c));
    return palindromo_estrito(normalizada);
}

Observação importante: Para ler linhas completas incluindo espaços, utilize getline(cin, variavel) em vez do operador >>.

Conversão Numérica entre Bases

Implementação de conversão de decimal para bases arbitrárias (2-36).

#include <iostream>
#include <string>
#include <algorithm>

std::string decimal_para_base(int valor, int base = 2);

int main() {
    int numero;
    while(std::cin >> numero) {
        std::cout << "Valor: " << numero << '\n'
                  << "Base 2:  " << decimal_para_base(numero) << '\n'
                  << "Base 8:  " << decimal_para_base(numero, 8) << '\n'
                  << "Base 16: " << decimal_para_base(numero, 16) << "\n\n";
    }
}

std::string decimal_para_base(int valor, int base) {
    if(valor == 0) return "0";
    
    bool negativo = valor < 0;
    unsigned int absoluto = negativo ? -valor : valor;
    
    std::string resultado;
    while(absoluto > 0) {
        int digito = absoluto % base;
        resultado += (digito < 10) ? ('0' + digito) : ('A' + digito - 10);
        absoluto /= base;
    }
    
    if(negativo) resultado += '-';
    std::reverse(resultado.begin(), resultado.end());
    return resultado;
}

Tabela de Cifras com Rotação

Geração de tabela de substituição com deslocamento progressivo.

#include <iostream>
#include <string>
#include <iomanip>
#include <algorithm>

int main() {
    using namespace std;
    
    string alfabeto;
    for(char c = 'A'; c <= 'Z'; ++c)
        alfabeto += c;
    
    cout << right << setw(4) << " ";
    for(auto c : alfabeto)
        cout << setw(3) << c;
    cout << '\n';
    
    string rotacionado = alfabeto;
    for(int i = 1; i <= 26; ++i) {
        cout << setw(3) << i;
        for(auto c : rotacionado)
            cout << setw(3) << c;
        cout << '\n';
        rotate(rotacionado.begin(), rotacionado.begin() + 1, rotacionado.end());
    }
}

Sistema de Questões Matemáticas

Gerador de exercícios aritméticos com validação de respostas.

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>

char operador_para_char(int codigo);
int executar_operacao(int codigo, int a, int b);

int main() {
    srand(static_cast<unsigned>(time(nullptr)));
    
    int acertos = 0;
    const int total_questoes = 10;
    
    for(int i = 0; i < total_questoes; ++i) {
        int operacao = rand() % 4;
        int operando1, operando2;
        bool valido = false;
        
        while(!valido) {
            operando1 = rand() % 10 + 1;
            operando2 = rand() % 10 + 1;
            
            switch(operacao) {
                case 1: valido = operando1 >= operando2; break;
                case 3: valido = operando1 % operando2 == 0; break;
                default: valido = true;
            }
        }
        
        int resposta_usuario;
        cout << operando1 << operador_para_char(operacao) 
             << operando2 << " = ";
        cin >> resposta_usuario;
        
        if(resposta_usuario == executar_operacao(operacao, operando1, operando2))
            ++acertos;
    }
    
    cout << "\nDesempenho: " << fixed << setprecision(1)
         << (acertos * 100.0 / total_questoes) << "%\n";
}

char operador_para_char(int codigo) {
    const char simbolos[] = {'+', '-', '*', '/'};
    return simbolos[codigo];
}

int executar_operacao(int codigo, int a, int b) {
    switch(codigo) {
        case 0: return a + b;
        case 1: return a - b;
        case 2: return a * b;
        case 3: return a / b;
        default: return 0;
    }
}

Tags: C++ STL algorithms reverse rotate

Publicado em 8-4 22:18