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óriareverse_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;
}
}