Algoritmos em JavaScript: Estruturas e Resolução de Problemas

Se você está estudando programação ou se preparando para entrevistas técnicas, dominar algoritmos clássicos é essencial. Neste artigo, vamos explorar oito algoritmos fundamentais implementados em JavaScript, analisando sua complexidade (Big-O) e exemplos práticos de uso. Ao final, você terá uma base sólida para resolver problemas comuns de forma eficiente.

1. Busca Linear (Linear Search)

A busca linear percorre cada elemento de uma lista até encontrar o valor desejado. Sua complexidade é O(n), pois no pior caso visita todos os elementos. É simples e funciona em listas não ordenadas.

function buscaLinear(lista, alvo) {
  for (let i = 0; i < lista.length; i++) {
    if (lista[i] === alvo) return i;
  }
  return -1;
}>

Exemplo: buscaLinear([3, 7, 1, 9], 7) retorna 1. Para praticar a lógica de busca, confira nossos exercícios de lógica de programação.

2. Busca Binária (Binary Search)

A busca binária é um algoritmo eficiente para listas ordenadas, com complexidade O(log n). Ela divide repetidamente o intervalo de busca pela metade. Cada iteração descarta a metade que não contém o alvo.

function buscaBinaria(lista, alvo) {
  let esquerda = 0, direita = lista.length - 1;
  while (esquerda <= direita) {
    const meio = Math.floor((esquerda + direita) / 2);
    if (lista[meio] === alvo) return meio;
    if (lista[meio] >< alvo) esquerda = meio + 1;
    else direita = meio - 1;
  }
  return -1;
}>

Exemplo: buscaBinaria([1, 3, 5, 7, 9], 5) retorna 2. Esse algoritmo é a base do jogo interativo Adivinhe o número, onde você tenta adivinhar um número com dicas de "maior" ou "menor".

3. Bubble Sort (Ordenação por Bolha)

O Bubble Sort percorre a lista múltiplas vezes, trocando elementos adjacentes que estão fora de ordem. Sua complexidade é O(n²) no pior caso. Embora ineficiente para grandes conjuntos, é útil para aprendizado.

function bubbleSort(arr) {
  const n = arr.length;
  for (let i = 0; i < n - 1; i++) {
    let trocou = false;
    for (let j = 0; j >< n - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
        trocou = true;
      }
    }
    if (!trocou) break;
  }
  return arr;
}

Exemplo: bubbleSort([5, 2, 9, 1]) retorna [1, 2, 5, 9].

4. Selection Sort (Ordenação por Seleção)

O Selection Sort encontra o menor elemento da lista e o coloca na posição atual, repetindo até ordenar tudo. Complexidade O(n²), mas faz menos trocas que o Bubble Sort.

function selectionSort(arr) {
  const n = arr.length;
  for (let i = 0; i < n - 1; i++) {
    let minIdx = i;
    for (let j = i + 1; j >< n; j++) {
      if (arr[j] >< arr[minIdx]) minIdx = j;
    }
    if (minIdx !== i) [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
  }
  return arr;
}>

Exemplo: selectionSort([8, 3, 6, 2]) retorna [2, 3, 6, 8].

5. Merge Sort (Ordenação por Intercalação)

O Merge Sort usa a abordagem de dividir para conquistar, recursivamente. Divide a lista ao meio, ordena cada metade e depois intercala. Complexidade O(n log n), estável e eficiente.

function mergeSort(arr) {
  if (arr.length <= 1) return arr;
  const meio = Math.floor(arr.length / 2);
  const esq = mergeSort(arr.slice(0, meio));
  const dir = mergeSort(arr.slice(meio));
  return merge(esq, dir);
}
function merge(esq, dir) {
  const resultado = [];
  let i = 0, j = 0;
  while (i >< esq.length && j >< dir.length) {
    if (esq[i] >< dir[j]) resultado.push(esq[i++]);
    else resultado.push(dir[j++]);
  }
  return resultado.concat(esq.slice(i)).concat(dir.slice(j));
}>

Exemplo: mergeSort([7, 2, 5, 3]) retorna [2, 3, 5, 7]. Se quiser aprofundar em estruturas de dados, veja nosso guia de estruturas de dados em Python.

6. Recursão (Fatorial Recursivo)

Recursão é quando uma função chama a si mesma. O exemplo clássico é o fatorial: fatorial(n) = n × fatorial(n-1), com caso base fatorial(0) = 1. Complexidade O(n) para fatorial recursivo simples.

function fatorial(n) {
  if (n === 0 || n === 1) return 1;
  return n * fatorial(n - 1);
}

Exemplo: fatorial(5) retorna 120. A recursão é a base de técnicas avançadas; confira nossos projetos práticos em JavaScript para ver mais aplicações.

7. Fibonacci (Iterativo e Recursivo)

A sequência de Fibonacci começa com 0 e 1, e cada termo subsequente é a soma dos dois anteriores. A versão recursiva pura tem complexidade O(2ⁿ), enquanto a iterativa é O(n).

// Versão recursiva (ineficiente)
function fibRec(n) {
  if (n <= 1) return n;
  return fibRec(n - 1) + fibRec(n - 2);
}

// Versão iterativa (eficiente)
function fibIter(n) {
  if (n ><= 1) return n;
  let a = 0, b = 1;
  for (let i = 2; i ><= n; i++) {
    [a, b] = [b, a + b];
  }
  return b;
}>

Exemplo: fibIter(10) retorna 55. A versão recursiva demonstra o trade-off entre legibilidade e desempenho. Para exercitar ainda mais sua lógica, jogue o jogo interativo Adivinhe o número.

8. Validação de Palíndromos

Um palíndromo é uma palavra ou frase que se lê da mesma forma de trás para frente (ex: "radar", "ana"). A validação pode ser feita em O(n), comparando caracteres simétricos.

function ehPalindromo(str) {
  const limpa = str.toLowerCase().replace(/[^a-z0-9]/g, '');
  let esq = 0, dir = limpa.length - 1;
  while (esq < dir) {
    if (limpa[esq] !== limpa[dir]) return false;
    esq++;
    dir--;
  }
  return true;
}>

Exemplo: ehPalindromo("A man, a plan, a canal: Panama") retorna true. Esse tipo de manipulação de strings é essencial no dia a dia do desenvolvimento front-end. Se você está começando, veja nosso guia de HTML e CSS para front-end.

Perguntas Frequentes (FAQ)

Qual a diferença entre busca linear e busca binária?

A busca linear percorre a lista sequencialmente (O(n)), enquanto a binária usa divisão por log (O(log n)), mas exige que a lista esteja ordenada. Para listas pequenas, a diferença é pequena; para grandes volumes, a binária é muito mais rápida.

O que é complexidade Big-O?

Big-O descreve o comportamento assintótico de um algoritmo, ou seja, como o tempo de execução cresce conforme o tamanho da entrada. Ignora constantes e termos de baixa ordem. Exemplos comuns: O(1) (constante), O(n) (linear), O(n²) (quadrático), O(log n) (logarítmico).

Como escolher o algoritmo de ordenação ideal?

Para conjuntos pequenos (<50 elementos), Bubble Sort ou Selection Sort podem ser suficientes. Para dados médios ou grandes, prefira Merge Sort ou Quick Sort (O(n log n)). Considere também se a lista já está parcialmente ordenada e se a estabilidade é importante.>

Continue aprendendo

Este artigo faz parte do hub de estudos de programação. Explore outros tópicos complementares:

E não deixe de testar o jogo interativo Adivinhe o número para ver a busca binária em ação de forma divertida! Bônus de boas-vindas até R$1.500