Estruturas de dados: questões para praticar com explicações
Questões de múltipla escolha grátis de Estruturas de dados, com dicas e explicações, em três níveis: termos e factos essenciais, aplicar os conceitos, casos e análise.
Uma estrutura de dados é uma forma de organizar dados na memória para que certas operações sejam rápidas: encontrar um item, inserir um, remover um.
Nenhuma estrutura é rápida em tudo. Escolher uma significa escolher quais operações devem ser baratas. Seus custos são escritos em notação Big O, com n o número de itens.
Os dois blocos básicos são o vetor (array) e a lista encadeada.
Um vetor (array) guarda seus itens num único bloco de memória, um depois do outro. O computador calcula onde está o item i, então ler a[i] custa O(1). Inserir no início exige deslocar todos os itens: O(n).
Uma lista encadeada guarda cada item num nó com um ponteiro para o próximo nó. O último ponteiro é nulo (null). Inserir na cabeça (h) altera apenas um ponteiro: O(1). Mas, para chegar ao item i, é preciso seguir i ponteiros: O(n).
Uma lista duplamente encadeada também tem um ponteiro para o nó anterior, então é possível percorrê-la nos dois sentidos.
Autoavaliação Qual operação é O(1) num vetor, mas O(n) numa lista simplesmente encadeada?
Contar os itens um a um
Inserir um novo item no início
Ler o item no índice i
Visitar cada item uma vez
Resposta: Ler o item no índice i. Um vetor calcula diretamente o endereço do item i. Uma lista encadeada precisa seguir i ponteiros a partir da cabeça. Inserir no início é o caso oposto: barato para a lista, caro para o vetor.
2Pilhas e filas
Uma pilha (stack) é como uma pilha de pratos: só se adiciona e remove no topo. O último a entrar é o primeiro a sair: LIFO.
push coloca um item no topo, pop remove o item do topo, peek lê o topo sem remover. Todas custam O(1).
Usos: a função desfazer de um editor, a pilha de chamadas de um programa, a verificação de parênteses balanceados, a busca em profundidade.
Uma fila (queue) é como a fila de um caixa: entra-se no fim e sai-se no início. O primeiro a entrar é o primeiro a sair: FIFO.
enqueue adiciona no fim, dequeue remove do início. Ambas custam O(1).
Usos: trabalhos de impressão, mensagens esperando para serem tratadas, busca em largura.
Uma deque (fila de duas pontas) permite adicionar e remover nas duas extremidades. Uma fila de prioridade sempre remove primeiro o item de maior prioridade; costuma ser construída como um heap.
Autoavaliação Qual estrutura de dados é a mais adequada para o botão “desfazer” de um editor de texto?
Um grafo
Uma fila
Uma pilha
Uma tabela hash
Resposta: Uma pilha. Desfazer deve reverter primeiro a ação mais recente: último a entrar, primeiro a sair. Uma fila desfaria primeiro a ação mais antiga.
3Árvores, heaps, tabelas hash e grafos
Uma árvore tem um nó no topo, a raiz. Todo outro nó tem exatamente um pai. Nós sem filhos são folhas. Uma árvore com n nós tem n − 1 arestas.
Numa árvore binária, cada nó tem no máximo dois filhos. Uma árvore binária de busca (BST) acrescenta uma regra: as chaves da subárvore esquerda são menores que o nó, as da subárvore direita são maiores.
A busca numa BST segue um único caminho para baixo, então custa O(altura). Uma árvore balanceada (AVL, rubro-negra) mantém a altura próxima de log₂ n. Chaves inseridas em ordem crescente formam uma cadeia de altura n.
Um heap é uma árvore binária em que todo pai é menor que seus filhos (min-heap) ou maior (max-heap). O mínimo ou o máximo está na raiz, e inserir e remover custam O(log n).
Uma tabela hash guarda pares chave–valor. Uma função hash transforma a chave em um índice, então inserir e buscar levam O(1) em média. Duas chaves com o mesmo índice formam uma colisão, resolvida por encadeamento (uma lista por posição) ou por endereçamento aberto (tentar outra posição).
Um grafo tem vértices ligados por arestas, que podem ter direção ou peso. É armazenado como matriz de adjacência, com memória O(V²), ou como listas de adjacência, O(V + E).
Autoavaliação As chaves 50, 30, 70, 20 e 40 são inseridas, nesta ordem, numa árvore binária de busca vazia. Qual é o filho esquerdo de 30?
20
40
70
Ele não tem filho esquerdo
Resposta: 20. 20 é menor que 50, então vai para a esquerda até o 30. Também é menor que 30, então vai de novo para a esquerda. 40 é maior que 30 e torna-se seu filho direito.
4O método passo a passo
As questões costumam descrever uma tarefa e perguntar qual estrutura se adequa, ou perguntar como fica uma estrutura depois de algumas operações.
Encontre a operação que precisa ser rápida: acesso por posição, por chave, o item mais novo, o mais antigo, o menor ou um intervalo.
Associe-a a uma estrutura: índice → vetor, chave → tabela hash, mais novo → pilha, mais antigo → fila, menor ou maior → heap, ordem ou intervalos → árvore de busca balanceada.
Verifique o custo das outras operações de que a tarefa precisa, em Big O.
Numa questão de simulação, execute as operações uma de cada vez e anote o estado após cada uma.
Confira o estado final com a regra da estrutura: LIFO, FIFO, a ordem da BST ou a ordem do heap.
5Um exemplo resolvido
Acompanhe cada passo. Tente prever o próximo antes de abri-lo.
Exemplo resolvido
As chaves 50, 30, 70, 20, 40 e 60 são inseridas, nesta ordem, numa árvore binária de busca vazia. Qual é o percurso em ordem (in-order) e quantas comparações a busca pelo 60 exige?
1
Insira a raiz
A primeira chave, 50, torna-se a raiz.
2
Insira 30 e 70
30 é menor que 50, então vai para a esquerda. 70 é maior que 50, então vai para a direita.
3
Insira 20, 40 e 60
20: menor que 50, menor que 30, então à esquerda de 30. 40: menor que 50, maior que 30, então à direita de 30. 60: maior que 50, menor que 70, então à esquerda de 70.
4
Percorra em ordem
Um percurso em ordem (in-order) visita a subárvore esquerda, depois o nó, depois a subárvore direita.
Isso dá 20, 30, 40, 50, 60, 70: as chaves em ordem crescente, como sempre acontece numa BST.
5
Busque o 60
Compare com 50: maior, vá para a direita. Compare com 70: menor, vá para a esquerda. Compare com 60: encontrado.
A busca exige 3 comparações, uma por nível.
Resposta
Em ordem: 20, 30, 40, 50, 60, 70. A busca pelo 60 exige 3 comparações.
6Erros comuns
Confundir LIFO e FIFO. Uma pilha devolve o item mais novo, uma fila o mais antigo.
Achar que uma lista encadeada dá acesso rápido por índice. Ela precisa percorrer a partir da cabeça.
Supor que uma BST é sempre O(log n). Só uma árvore balanceada é; inserções em ordem crescente dão O(n).
Esquecer as colisões numa tabela hash. O(1) é a média, não o pior caso.
Confundir os percursos. Pré-ordem: nó primeiro. Em ordem: nó no meio. Pós-ordem: nó por último.
Usar uma matriz de adjacência para um grafo grande e esparso. Ela desperdiça memória O(V²).
Autoavaliação Você enfileira (enqueue) 1, 2 e 3 numa fila vazia, nesta ordem. Qual item o primeiro dequeue devolve?
1, 2 e 3 juntos
1
2
3
Resposta: 1. Uma fila é primeiro a entrar, primeiro a sair, então o 1 sai primeiro. O 3 seria a resposta para uma pilha (pop), que devolve o item mais novo.
7Como são as questões de prova
Fácil: termos e fatos essenciais. LIFO e FIFO, o que é um nó, uma raiz ou uma folha, a regra da BST, o que faz uma função hash.
Médio: aplicação dos conceitos. Qual estrutura se adequa a uma tarefa, o resultado de push e pop ou de inserções numa BST, percursos de árvores, uma tabela hash com sondagem linear, custos em Big O.
Difícil: casos e análise. Árvores balanceadas, heaps em vetores, árvores B, tries, union-find, filtros de Bloom e projetos como um cache LRU.
Para um heap guardado num vetor a partir do índice 0, os filhos do índice i estão em 2i + 1 e 2i + 2, e o pai está em ⌊(i − 1) / 2⌋.
Qual é a principal diferença entre um array estático e um array dinâmico?
AUm array estático tem acesso por índice mais lento
BUm array dinâmico pode crescer passando para um bloco de memória maior
CUm array dinâmico armazena seus elementos em nós encadeados para poder crescer um de cada vez
DUm array estático só pode armazenar números
Mostrar dicas
As listas do Python e os ArrayLists do Java são exemplos de um deles.
Agora há duas respostas erradas riscadas. Uma das duas que restam está certa.
Mostrar a resposta e a explicação
Porque é esta a resposta
Um array estático tem tamanho fixo; um array dinâmico aloca um array maior e copia os elementos quando fica cheio.
Resposta
B · Um array dinâmico pode crescer passando para um bloco de memória maior
Exemplo 2Média
Como funciona o extract-min em um min-heap binário?
ARemove-se o último elemento do array
BMove-se o último elemento para a raiz e faz-se sift-down
CRemove-se a raiz e desloca-se todos os elementos uma posição à esquerda
DProcura-se o novo mínimo em todas as folhas
Mostrar dicas
Mantenha a árvore completa e depois corrija a ordem.
Agora há duas respostas erradas riscadas. Uma das duas que restam está certa.
Mostrar a resposta e a explicação
Porque é esta a resposta
O último elemento preenche o buraco na raiz e é trocado com o menor filho até a propriedade de heap valer, em O(log n).
Resposta
B · Move-se o último elemento para a raiz e faz-se sift-down
Exemplo 3Difícil
Sem união por posto nem compressão de caminho, qual é o custo no pior caso de um único find em uma estrutura union-find com n elementos?
AO(1)
BO(α(n))
CO(log n)
DO(n)
Mostrar dicas
As árvores podem degenerar.
Agora há duas respostas erradas riscadas. Uma das duas que restam está certa.
Mostrar a resposta e a explicação
Porque é esta a resposta
Uniões ingênuas podem ligar as árvores em uma longa cadeia, então o find pode seguir n − 1 ponteiros para o pai; as duas heurísticas o deixam perto de constante.
Resposta
D · O(n)
Perguntas e respostas
Estruturas de dados: o que é?
Uma estrutura de dados é uma forma de organizar dados na memória para que certas operações sejam rápidas: encontrar um item, inserir um, remover um.
Nenhuma estrutura é rápida em tudo. Escolher uma significa escolher quais operações devem ser baratas. Seus custos são escritos em notação Big O, com n o número de itens.
Estruturas de dados: como aprender passo a passo?
O que é uma estrutura de dados
Pilhas e filas
Árvores, heaps, tabelas hash e grafos
O método passo a passo
Um exemplo resolvido
Erros comuns
Como são as questões de prova
Estruturas de dados: o que se pratica?
Fácil: termos e factos essenciais
Média: aplicar os conceitos
Difícil: casos e análise
Cada questão tem quatro alternativas, e só uma está certa. Travou? Abra primeiro uma dica pequena, e a explicação completa só quando precisar.
Como a prática funciona
Cada questão tem quatro alternativas, e só uma está certa.
Travou? Abra primeiro uma dica pequena, e a explicação completa só quando precisar.
Seu progresso, seus erros e seus exercícios salvos ficam guardados, para você revisar antes da prova.