Módulo 3 · Algoritmos e Estruturas de Dados — Capítulo 02

Vetores e Matrizes

A estrutura de dados mais básica de todas — e a base para entender por que algumas operações são instantâneas e outras não.

1. O que é um vetor

Um vetor (também chamado de array) é uma coleção de itens organizados em sequência, guardados em blocos de memória contíguos — ou seja, um exatamente ao lado do outro, sem espaço entre eles. Cada item tem uma posição fixa chamada índice, que começa em zero.

Você já usa essa estrutura constantemente em JavaScript — todo [] é, na essência, um vetor (embora arrays de JS tenham flexibilidades extras que vetores "puros" de outras linguagens não têm, como redimensionar automaticamente e misturar tipos). O que importa entender agora é o comportamento fundamental por trás dessa estrutura, que é o mesmo em qualquer linguagem de programação.

vetor de 6 posições, guardado em memória contígua 12 7 45 3 89 21 índice 0 índice 1 índice 2 índice 3 índice 4 índice 5 acessar vetor[índice] é O(1): o endereço é calculado direto, sem percorrer nada

Fig. 1 — Um vetor é um bloco contíguo de memória; cada índice aponta direto para uma posição.

2. Acesso por índice é O(1)

A razão pela qual vetor[3] é instantâneo, não importa se o vetor tem 10 ou 10 milhões de posições, é a mesma razão pela qual o vetor precisa ser contíguo em memória: o computador calcula o endereço exato daquela posição com uma conta simples (endereço inicial + índice × tamanho de cada item) e vai direto lá. Não é necessário percorrer nada antes.

PSEUDOCÓDIGO acesso.txt
números ← [12, 7, 45, 3, 89, 21]
ESCREVA números[2]   // 45 — acesso direto, O(1)

3. Percorrer um vetor

A operação mais comum sobre um vetor é visitar cada item, um de cada vez — e isso, como visto no capítulo anterior, é O(n): o trabalho cresce proporcionalmente ao tamanho do vetor.

PSEUDOCÓDIGO percorrer.txt
FUNÇÃO imprimirTodos(vetor)
    PARA i DE 0 ATÉ tamanho(vetor) - 1
        ESCREVA vetor[i]
    FIM PARA
FIM FUNÇÃO

4. Inserir e remover: nem tudo é O(1)

Acessar por índice é rápido, mas inserir e remover itens tem um custo que depende de onde na estrutura a operação acontece.

Inserir ou remover no final do vetor é O(1) — não precisa mexer em mais nada, só adicionar ou tirar a última posição. Mas inserir ou remover no meio ou no início é O(n): como o vetor precisa continuar contíguo, todo item depois da posição afetada precisa ser deslocado uma casa para a esquerda (ao remover) ou para a direita (ao inserir).

PSEUDOCÓDIGO remover-do-meio.txt
FUNÇÃO removerNoÍndice(vetor, índice)
    PARA i DE índice ATÉ tamanho(vetor) - 2
        vetor[i] ← vetor[i + 1]   // desloca cada item uma casa
    FIM PARA
    diminuirTamanho(vetor)
FIM FUNÇÃO
Atenção

É um erro comum achar que array.splice(0, 1) ou array.shift() em JavaScript são operações "baratas" só porque a sintaxe é uma linha só. Por baixo, remover o primeiro item de um array força o motor da linguagem a deslocar todos os outros itens — é O(n), do mesmo jeito que no pseudocódigo acima. A sintaxe curta esconde o custo, mas não elimina ele.

5. Matrizes: vetores de duas dimensões

Uma matriz é a extensão natural do vetor para duas dimensões: em vez de uma fila de posições, é uma tabela organizada em linhas e colunas. Cada elemento é acessado por dois índices — linha e coluna.

Pense numa planilha, num tabuleiro de jogo da velha, ou num mapa de pixels de uma imagem: todos são exemplos naturais de matriz. Na prática, a forma mais comum de representar uma matriz é como "um vetor de vetores" — cada posição do vetor externo guarda um vetor interno representando uma linha.

matriz 3×4 (3 linhas, 4 colunas) col 0 col 1 col 2 col 3 lin 0 lin 1 lin 2 matriz[1][1] acesso: matriz[linha][coluna] — dois índices em vez de um

Fig. 2 — Uma matriz é acessada por dois índices: linha e coluna.

6. Percorrendo uma matriz com loops aninhados

Para visitar cada elemento de uma matriz, é preciso um laço dentro de outro: o laço externo percorre as linhas, e para cada linha, o laço interno percorre as colunas. Isso é O(n × m), onde n é o número de linhas e m o número de colunas — se a matriz for quadrada (mesmo número de linhas e colunas), isso vira O(n²).

PSEUDOCÓDIGO percorrer-matriz.txt
FUNÇÃO imprimirMatriz(matriz)
    PARA linha DE 0 ATÉ numeroDeLinhas(matriz) - 1
        PARA coluna DE 0 ATÉ numeroDeColunas(matriz) - 1
            ESCREVA matriz[linha][coluna]
        FIM PARA
    FIM PARA
FIM FUNÇÃO

7. Quando escolher vetor (ou matriz)

Vetores e matrizes são a estrutura certa quando: você sabe (ou consegue estimar) o tamanho dos dados de antemão, o acesso por posição/índice é uma operação frequente, e inserções ou remoções no meio da coleção são raras. Quando remoções e inserções no início/meio da coleção são a operação mais comum, existe uma estrutura mais adequada — a lista encadeada, assunto do capítulo 4.

📌 Resumo do capítulo

  • Vetor: coleção guardada em memória contígua, com acesso por índice numérico a partir de zero.
  • Acessar um item por índice é O(1) — o endereço é calculado direto, não é preciso percorrer nada.
  • Percorrer todos os itens de um vetor é O(n).
  • Inserir/remover no final é O(1); inserir/remover no início ou meio é O(n), porque exige deslocar os itens seguintes.
  • Matriz é a versão bidimensional do vetor: acesso por dois índices, linha e coluna.
  • Percorrer uma matriz inteira exige laços aninhados — O(n × m), ou O(n²) se for quadrada.
  • Vetores são ideais quando o acesso por posição é frequente e inserções/remoções no meio são raras.

✏️ Praticando

  1. Escreva em pseudocódigo uma função que recebe um vetor de números e retorna a soma de todos os elementos. Qual a complexidade?
  2. Escreva em pseudocódigo uma função que recebe um vetor e um valor, e insere esse valor na primeira posição, deslocando todos os outros itens uma casa para a direita. Qual a complexidade dessa operação e por quê?
  3. Dado o pseudocódigo da seção 4 (removerNoÍndice), explique com suas palavras por que remover o último elemento de um vetor de 1000 posições é muito mais rápido do que remover o primeiro.
  4. Escreva em pseudocódigo uma função que recebe uma matriz quadrada (mesmo número de linhas e colunas) e retorna a soma de todos os elementos da diagonal principal (onde linha = coluna).
  5. Pense num sistema real (por exemplo, uma planilha de notas de alunos por disciplina). Modele isso como uma matriz: o que representam as linhas? E as colunas?