Lógica e Algoritmos
Subtópico da área de Programação com foco em raciocínio algorítmico, estruturas fundamentais e implementação prática em Python e C++.
Fundamentos Algorítmicos e Paradigmas
Comparativo de Abordagem: Python vs. C++
| Característica | Python | C++ |
|---|---|---|
| Tipagem | Dinâmica e Forte (interpretado em tempo de execução). | Estática e Forte (compilado para código de máquina). |
| Gerenciamento de Memória | Automático via Garbage Collector e Contagem de Referências. | Manual ou via Smart Pointers (RAII). Perto do hardware. |
| Foco de Aplicação | Prototipagem rápida, Data Science, Automação, Scripting. | Sistemas operacionais, Game Engines, Programação de Baixo Nível. |
1. Variáveis, Tipos de Dados e Atribuição
Variáveis são posições nomeadas de memória reservadas para armazenar dados durante a execução.
- Inteiros (int): Números sem casa decimal. Ex:
-5,42. - Ponto Flutuante (float/double): Números reais. Ex:
3.14159. - Caracteres e Strings (char, str): Texto puro ou sequências de caracteres.
- Booleanos (bool): Valores lógicos
True/False(Python) outrue/false(C++).
2. Operadores Aritméticos, Relacionais e Lógicos
Combinam valores e variáveis para retornar novos dados ou decisões booleanas.
- Relacionais: Igualdade (
==), Diferença (!=), Maior (>), Menor (<), Maior/Igual (>=). - Lógicos (AND / E): Retorna verdadeiro se **ambas** as condições forem verdadeiras.
- Lógicos (OR / OU): Retorna verdadeiro se **ao menos uma** condição for verdadeira.
- Negação (NOT / NÃO): Inverte o valor lógico de uma expressão.
3. Controle de Fluxo Condicional
Altera o caminho de execução do código com base em condições lógicas.
Estruturas if / else / elif
Exemplo de verificação de maioridade ou categorias de acesso:
# Python: Estruturas Condicionais
idade = 18
if idade >= 18:
print("Acesso Concedido: Maior de Idade")
elif idade >= 16:
print("Acesso Concedido com Autorização")
else:
print("Acesso Negado")
// C++: Estruturas Condicionais
#include <iostream>
int main() {
int idade = 18;
if (idade >= 18) {
std::cout << "Acesso Concedido: Maior de Idade\n";
} else if (idade >= 16) {
std::cout << "Acesso Concedido com Autorizacao\n";
} else {
std::cout << "Acesso Negado\n";
}
return 0;
}
4. Laços de Repetição (Loops)
Iteram sobre blocos de código enquanto uma condição for satisfeita ou por uma quantidade definida de passos.
Iteração Determinada (For) e Indeterminada (While)
# Python: Loop For e While
# Imprimir de 0 a 4
for i in range(5):
print(f"Iteracao For: {i}")
# Loop controlado por condição
contador = 0
while contador < 3:
print(f"Iteracao While: {contador}")
contador += 1
// C++: Loop For e While
#include <iostream>
int main() {
// Loop For
for (int i = 0; i < 5; i++) {
std::cout << "Iteracao For: " << i << "\n";
}
// Loop While
int contador = 0;
while (contador < 3) {
std::cout << "Iteracao While: " << contador << "\n";
contador++;
}
return 0;
}
5. Estruturas de Dados Homogêneas: Arrays e Listas
Coleções contíguas de dados acessadas via índices numéricos indexados em zero.
- Indexação Directa: Acessar elemento na posição $N$ possui custo constante $\mathcal{O}(1)$.
- Python List: Array dinâmico capaz de redimensionar automaticamente e guardar tipos mistos.
- C++ std::vector / Array: O
std::vectorprovê redimensionamento dinâmico em memória contígua.
6. Estruturas Multidimensionais: Matrizes
Arrays de arrays dispostos em linhas e colunas (grade bidimensional).
# Python: Matriz 2x3
matriz = [
[1, 2, 3],
[4, 5, 6]
]
for linha in matriz:
for elemento in linha:
print(elemento, end=" ")
print()
// C++: Matriz 2x3
#include <iostream>
int main() {
int matriz[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
std::cout << matriz[i][j] << " ";
}
std::cout << "\n";
}
return 0;
}
7. Funções, Parâmetros e Modularição
Blocos de código reutilizáveis projetados para realizar uma tarefa específica, recebendo entradas (parâmetros) e devolvendo saídas (retorno).
# Python: Definição de Função
def calcular_area_retangulo(base: float, altura: float) -> float:
return base * altura
resultado = calcular_area_retangulo(5.0, 3.0)
print(f"Area: {resultado}")
// C++: Definição de Função
#include <iostream>
double calcularAreaRetangulo(double base, double altura) {
return base * altura;
}
int main() {
double resultado = calcularAreaRetangulo(5.0, 3.0);
std::cout << "Area: " << resultado << "\n";
return 0;
}
8. Gerenciamento de Memória: Ponteiros e Referências
Enquanto linguagens de alto nível abstraem a memória, o C++ permite manipulação direta de endereços via ponteiros.
- Passagem por Valor: Uma cópia do dado é passada para a função (alterações locais não afetam o original).
- Passagem por Referência: Um alias ou o próprio endereço é passado (alterações afetam a variável original).
- Ponteiro (C++): Variável que guarda o endereço hexadecimal de outra variável na memória.
// C++: Demostração de Ponteiro e Referência
#include <iostream>
void incrementarPorReferencia(int &valor) {
valor++; // Altera diretamente o valor original
}
int main() {
int valor = 10;
int* ptr = &valor; // 'ptr' guarda o endereço de 'valor'
std::cout << "Valor Original: " << valor << "\n";
std::cout << "Endereco na RAM (&valor): " << ptr << "\n";
incrementarPorReferencia(valor);
std::cout << "Apos Incrementar: " << valor << "\n";
return 0;
}
9. Algoritmos de Busca
Métodos para localizar um elemento dentro de uma estrutura de dados.
Busca Linear vs. Busca Binária
| Algoritmo | Pré-requisito | Complexidade Pior Caso |
|---|---|---|
| Busca Linear | Nenhum (funciona em listas desordenadas). | $\mathcal{O}(n)$ — Percorre item por item. |
| Busca Binária | O array obrigatoriamente deve estar **ordenado**. | $\mathcal{O}(\log n)$ — Divide o espaço de busca pela metade a cada passo. |
# Python: Busca Binária Iterativa
def busca_binaria(arr, alvo):
inicio = 0
fim = len(arr) - 1
while inicio <= fim:
meio = (inicio + fim) // 2
if arr[meio] == alvo:
return meio # Retorna o índice encontrado
elif arr[meio] < alvo:
inicio = meio + 1
else:
fim = meio - 1
return -1 # Não encontrado
dados = [10, 20, 30, 40, 50, 60, 70]
print("Indice do 40:", busca_binaria(dados, 40))
10. Algoritmos de Ordenação
Reorganizam elementos de uma lista segundo uma ordem definida (crescente ou decrescente).
- Bubble Sort: Algoritmo simples, compara elementos adjacentes e os troca se estiverem fora de ordem ($\mathcal{O}(n^2)$).
- Insertion Sort: Constrói a lista ordenada final um item por vez ($\mathcal{O}(n^2)$).
- Merge Sort / Quick Sort: Algoritmos de divisão e conquista de alta performance ($\mathcal{O}(n \log n)$).
// C++: Bubble Sort
#include <iostream>
#include <vector>
void bubbleSort(std::vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Troca os elementos de lugar
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
int main() {
std::vector<int> lista = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(lista);
std::cout << "Lista Ordenada: ";
for (int x : lista) std::cout << x << " ";
std::cout << "\n";
return 0;
}
11. Análise de Complexidade de Algoritmos (Notação Big-O)
Mede a eficiência do tempo de execução ou do consumo de memória de um algoritmo à medida que o tamanho da entrada ($n$) cresce.
O(1)- Tempo Constante: Acesso direto a elemento de array.O(log n)- Tempo Logarítmico: Busca binária.O(n)- Tempo Linear: Percorrer uma lista de $n$ elementos.O(n log n)- Tempo Linear-Logarítmico: Merge Sort / Quick Sort médio.O(n²)- Tempo Quadrático: Loops aninhados (Bubble Sort).
12. Boas Práticas e Legibilidade de Código
- Nomes Significativos: Prefira nomes descritivos (ex:
total_vendas) sobre nomes vagos (ex:x,data). - Princípio DRY (Don't Repeat Yourself): Se um bloco de código se repete, transforme-o em uma função reutilizável.
- Indentação e Formatação: Mantenha a consistência (ex: 4 espaços para Python ou padrão da equipe para C++).
- Comentários Úteis: Explique o **porquê** a regra de negócio existe, não o que a linguagem já deixa óbvio.
13. Técnicas de Depuração (Debugging)
Diagnóstico sistemático para localizar e corrigir bugs no fluxo lógico.
- Dry Run (Teste de Mesa): Acompanhar a execução do algoritmo passo a passo manualmente com papel e caneta.
- Print Debugging: Inserir saídas temporárias no terminal para inspecionar o estado interno de variáveis.
- Breakpoints & Step-Over: Executar o código em uma IDE conectada a um depurador (GDB, PDB) pausando a execução em pontos específicos.
ANEXO A — Checklist de Validação Algorítmica
- O algoritmo possui uma condição clara de parada/término para evitar loops infinitos?
- Todos os caminhos de controle (if / else / switch) cobrem todos os casos de borda possíveis?
- As variáveis foram inicializadas com valores válidos antes da primeira leitura?
- Estruturas de índice (Arrays/Vectors) checam se o índice acessado está dentro dos limites válidos?
- As entradas do usuário são tratadas e validadas contra tipos e dados inconsistentes?
ANEXO B — Tabela Verdade dos Operadores Lógicos
| Condição A | Condição B | A AND B | A OR B | NOT A |
|---|---|---|---|---|
| V (True) | V (True) | V (True) | V (True) | F (False) |
| V (True) | F (False) | F (False) | V (True) | F (False) |
| F (False) | V (True) | F (False) | V (True) | V (True) |
| F (False) | F (False) | F (False) | F (False) | V (True) |
ANEXO C — Exemplos de Manipulação de Entrada e Saída
Python (Leitura de Dados)
# Leitura e conversão de tipos em Python
nome = input("Digite seu nome: ")
idade = int(input("Digite sua idade: "))
altura = float(input("Digite sua altura (m): "))
print(f"Usuario {nome}, {idade} anos, {altura}m de altura.")
C++ (Leitura de Dados)
// Leitura de dados em C++ usando std::cin
#include <iostream>
#include <string>
int main() {
std::string nome;
int idade;
double altura;
std::cout << "Digite seu nome: ";
std::cin >> nome;
std::cout << "Digite sua idade: ";
std::cin >> idade;
std::cout << "Digite sua altura: ";
std::cin >> altura;
std::cout << "Usuario " << nome << ", " << idade << " anos, " << altura << "m de altura.\n";
return 0;
}
ANEXO D — Comparativo de Escala da Notação Big-O
| Tamanho Entrada ($N$) | $\mathcal{O}(1)$ | $\mathcal{O}(\log n)$ | $\mathcal{O}(n)$ | $\mathcal{O}(n \log n)$ | $\mathcal{O}(n^2)$ |
|---|---|---|---|---|---|
| 10 | 1 op | ~3 ops | 10 ops | ~33 ops | 100 ops |
| 100 | 1 op | ~7 ops | 100 ops | ~664 ops | 10.000 ops |
| 1.000 | 1 op | ~10 ops | 1.000 ops | ~9.965 ops | 1.000.000 ops |