Estratégias de Otimização
Otimização de Algoritmos Recursivos
A otimização de algoritmos recursivos é crucial para melhorar o desempenho e a eficiência de memória. Esta seção explora técnicas avançadas para aprimorar o código recursivo.
Técnicas de Otimização
graph TD
A[Estratégias de Otimização] --> B[Recursão em Cauda]
A --> C[Memorização]
A --> D[Programação Dinâmica]
A --> E[Conversão Iterativa]
1. Otimização de Recursão em Cauda
// Função recursiva não otimizada
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
// Otimização recursiva em cauda
int fibonacci_optimized(int n, int a, int b) {
if (n == 0) return a;
if (n == 1) return b;
return fibonacci_optimized(n-1, b, a+b);
}
2. Técnica de Memorização
#define MAX_N 1000
int memo[MAX_N];
int fibonacci_memoized(int n) {
// Verificar resultado memorizado
if (memo[n] != -1) {
return memo[n];
}
// Calcular e armazenar o resultado
if (n <= 1) {
memo[n] = n;
} else {
memo[n] = fibonacci_memoized(n-1) + fibonacci_memoized(n-2);
}
return memo[n];
}
Comparação de Desempenho
| Técnica |
Complexidade de Tempo |
Complexidade de Espaço |
Prós |
Contras |
| Recursão Básica |
O(2^n) |
O(n) |
Simples |
Ineficiente |
| Memorização |
O(n) |
O(n) |
Eficiente |
Memória adicional |
| Recursão em Cauda |
O(n) |
O(1) |
Eficiente em memória |
Necessidade de suporte do compilador |
3. Abordagem de Programação Dinâmica
int fibonacci_dp(int n) {
if (n <= 1) return n;
int dp[n+1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
Flags de Otimização do Compilador
graph LR
A[Flags de Otimização do GCC] --> B[-O0: Sem otimização]
A --> C[-O1: Otimização básica]
A --> D[-O2: Nível recomendado]
A --> E[-O3: Otimização agressiva]
Estratégias de Otimização Avançadas
- Incorporação de Funções
- Dicas de Compilador
- Conversão Recursiva para Iterativa
Exemplo de Dica de Compilador
// Dica de função inline
__attribute__((always_inline))
int recursive_helper(int n) {
if (n <= 1) return n;
return n * recursive_helper(n-1);
}
Boas Práticas
- Preferir soluções iterativas quando possível
- Usar memorização para cálculos repetidos
- Aproveitar as flags de otimização do compilador
- Protelar e comparar o seu código
- Considerar as trocas espaço-tempo
Na LabEx, recomendamos uma abordagem sistemática à otimização de algoritmos recursivos, equilibrando legibilidade e desempenho.