O que são estruturas de dados e por que caem em prova
Estruturas de dados são formas de organizar e armazenar informações para permitir operações eficientes como inserção, remoção, busca e percurso (varredura). Em concursos, o foco costuma ser: (1) reconhecer a estrutura adequada para um cenário, (2) comparar custos de tempo (Big-O) e (3) entender o comportamento de operações típicas.
Operações fundamentais (linguagem-agnósticas)
Inserção
Adicionar um elemento à estrutura. O custo depende de onde a inserção ocorre (início, meio, fim) e se há necessidade de deslocar elementos ou realocar memória.
Remoção
Excluir um elemento. Pode exigir localizar o item (busca) e, em estruturas sequenciais, deslocar elementos para “fechar o buraco”.
Busca
Encontrar um elemento por valor/chave/posição. Pode ser por índice (acesso direto), por varredura (linear) ou por hashing (tabela de dispersão).
Percurso (travessia)
Visitar todos os elementos (por exemplo, para listar processos, gerar relatório, recalcular estatísticas). Em geral, custa O(n), pois cada item é visitado uma vez.
Continue em nosso aplicativo
Você poderá ouvir o audiobook com a tela desligada, ganhar gratuitamente o certificado deste curso e ainda ter acesso a outros 5.000 cursos online gratuitos.
ou continue lendo abaixo...Baixar o aplicativo
Vetores (arrays): acesso direto por índice
Conceito
Vetor (array) é uma coleção de elementos armazenados em posições contíguas de memória, acessadas por índice. É ideal quando você precisa de acesso rápido por posição (ex.: “pegar o 10º item”).
Operações e complexidade (nível de prova)
- Acesso por índice: O(1)
- Busca por valor (sem ordenação): O(n)
- Inserção/remoção no fim (se houver espaço): O(1); se precisar realocar (array dinâmico): amortizado O(1)
- Inserção/remoção no início ou meio: O(n) (deslocamento de elementos)
- Percurso: O(n)
Exemplo prático no Judiciário
Lista fixa de “tipos de movimentação” ou “códigos de situação” carregada em memória para consulta por índice (ou por posição conhecida). Se a coleção é pequena e raramente muda, arrays são simples e eficientes.
Passo a passo prático: inserir no meio de um array
Suponha um array de prioridades de tarefas [A, B, D, E] e você precisa inserir C na posição 2 (0-based: após B).
- 1) Verificar se há capacidade; se não houver, realocar para um array maior.
- 2) Deslocar elementos à direita a partir do fim: mover E para a próxima posição, depois D, etc.
- 3) Escrever C na posição desejada.
// ideia geral (pseudo-código) para inserir em i em array com tamanho n e capacidade cap if n == cap: realocar(cap*2) for k = n-1 downTo i: a[k+1] = a[k] a[i] = x n++Listas: flexibilidade para inserções/remoções
Conceito
“Lista” pode significar lista encadeada (linked list) ou lista baseada em array (array list). Em prova, a comparação mais comum é: arrays (contíguos) vs listas encadeadas (nós ligados por ponteiros). A lista encadeada é útil quando inserções/remoções frequentes ocorrem no início/meio e você já tem referência ao ponto de alteração.
Lista encadeada: operações e complexidade
- Acesso por posição (k-ésimo): O(n) (precisa caminhar nó a nó)
- Busca por valor: O(n)
- Inserção/remoção no início: O(1)
- Inserção/remoção no meio: O(1) se você já tem o nó anterior; caso precise localizar a posição antes: O(n)
- Percurso: O(n)
Diferenças-chave: arrays vs listas encadeadas
- Memória: array é contíguo; lista encadeada tem overhead de ponteiros por nó.
- Acesso aleatório: array é O(1) por índice; lista encadeada é O(n).
- Inserção/remoção no meio: array tende a O(n) por deslocamento; lista encadeada pode ser O(1) se o ponto já é conhecido.
- Localidade de cache: arrays costumam ser mais rápidos na prática para percursos, por estarem contíguos.
Exemplo prático no Judiciário
Em um módulo de “minutas em elaboração”, pode haver inserções e remoções frequentes de itens em posições específicas (por exemplo, reordenar uma pauta manualmente). Se o sistema mantém ponteiros/referências para itens (como nós), uma lista encadeada pode reduzir custo de movimentação, embora a busca por posição continue custosa.
Passo a passo prático: remover um item de lista encadeada
Para remover o nó com valor X:
- 1) Percorrer a lista mantendo dois ponteiros: anterior (prev) e atual (cur).
- 2) Ao encontrar X em cur, ajustar prev.next = cur.next.
- 3) Se X estiver no primeiro nó, atualizar o head para head.next.
// pseudo-código para remover primeira ocorrência de X prev = null cur = head while cur != null and cur.value != X: prev = cur cur = cur.next if cur == null: return // não achou if prev == null: head = cur.next else: prev.next = cur.nextPilhas (stacks): LIFO
Conceito
Pilha é uma estrutura em que o último elemento inserido é o primeiro a ser removido (LIFO: Last In, First Out). Operações típicas: push (empilhar), pop (desempilhar) e top/peek (consultar o topo).
Operações e complexidade
- push: O(1)
- pop: O(1)
- peek: O(1)
- Busca por valor: O(n) (se for necessário procurar)
- Percurso: O(n)
Caso prático no Judiciário: pilha de chamadas/execução
Em sistemas, uma pilha modela chamadas de funções (call stack) e também pode representar “desfazer/refazer” em editores de texto de minutas: cada ação é empilhada; ao desfazer, desempilha-se a última ação.
Passo a passo prático: desfazer ações (undo)
- 1) Ao executar uma ação (ex.: inserir parágrafo), empilhar um registro com dados para desfazer.
- 2) Ao solicitar “desfazer”, fazer pop e aplicar a operação inversa.
- 3) Opcional: empilhar a ação desfeita em outra pilha para permitir “refazer”.
// duas pilhas: undoStack e redoStack executar(acao): aplicar(acao) undoStack.push(acao) redoStack.clear() desfazer(): if undoStack.vazia(): return acao = undoStack.pop() aplicar(inversa(acao)) redoStack.push(acao)Filas (queues): FIFO
Conceito
Fila é uma estrutura em que o primeiro elemento inserido é o primeiro a ser removido (FIFO: First In, First Out). Operações típicas: enqueue (enfileirar), dequeue (desenfileirar) e front/peek (consultar o primeiro).
Operações e complexidade
- enqueue: O(1)
- dequeue: O(1)
- peek: O(1)
- Busca por valor: O(n)
- Percurso: O(n)
Caso prático no Judiciário: fila de atendimento e processamento
Uma fila modela bem: (1) distribuição de senhas em atendimento ao público, (2) processamento assíncrono de tarefas (ex.: geração de documentos, envio de intimações, indexação de peças) em ordem de chegada.
Passo a passo prático: fila de atendimento
- 1) Cada novo atendimento gera uma senha e é enfileirado (enqueue).
- 2) O guichê chama o próximo (dequeue).
- 3) Para exibir “próximos 5”, percorre-se a fila sem removê-la (percurso O(n) no pior caso, mas pode-se limitar a 5).
// pseudo-código de fila simples chegada(senha): fila.enqueue(senha) chamarProximo(): if fila.vazia(): return null return fila.dequeue()Mapas (dicionários): chave → valor
Conceito
Mapa (dicionário) armazena pares (chave, valor), permitindo recuperar rapidamente um valor a partir de uma chave. Implementações comuns: tabela hash (hash map) e árvore balanceada (tree map). Em prova, a tabela hash é frequentemente associada a busca média O(1).
Operações e complexidade (comparações simples)
Considerando um mapa baseado em hash:
- Inserção (put): O(1) em média; O(n) no pior caso (colisões extremas)
- Busca (get): O(1) em média; O(n) no pior caso
- Remoção (remove): O(1) em média; O(n) no pior caso
- Percorrer todas as entradas: O(n)
Considerando um mapa baseado em árvore balanceada (ex.: Red-Black):
- Inserção, busca e remoção: O(log n)
- Percurso em ordem de chaves: O(n)
Caso prático no Judiciário: índice de consulta
Mapas são ideais para indexação: por exemplo, consultar rapidamente um processo pelo número (chave) e obter seus metadados (valor). Também servem para mapear CPF/CNPJ para partes, ou ID de documento para localização no repositório.
Passo a passo prático: índice por número do processo
- 1) Definir a chave (ex.: numeroProcesso) e o valor (ex.: objeto Processo com classe, partes, movimentações).
- 2) Ao carregar/receber um processo, inserir no mapa: put(numeroProcesso, processo).
- 3) Para consulta, buscar por chave: get(numeroProcesso).
- 4) Para atualização, sobrescrever o valor na mesma chave.
// pseudo-código mapaProcessos = {} cadastrar(processo): mapaProcessos[processo.numero] = processo consultar(numero): return mapaProcessos.get(numero) // ou nullComparativo rápido (o que a banca costuma cobrar)
Quando escolher cada estrutura
- Array: acesso por índice muito frequente; tamanho relativamente estável; percursos rápidos.
- Lista encadeada: muitas inserções/remoções no início/meio quando já se tem referência ao ponto; acesso por índice não é prioridade.
- Pilha: desfazer ações, controle de execução, processamento reverso (LIFO).
- Fila: atendimento e processamento em ordem de chegada (FIFO), filas de tarefas.
- Mapa: consulta por chave (índice), associação direta chave→valor.
Tabela de Big-O (nível de prova)
Estrutura Acesso por índice Busca (valor) Inserção fim Inserção meio/início Remoção meio/início Array O(1) O(n) O(1)* O(n) O(n) Lista encad. O(n) O(n) O(1)** O(1)** / O(n)*** O(1)** / O(n)*** Pilha - O(n) O(1) - - Fila - O(n) O(1) - - Mapa (hash) - O(1) médio O(1) médio - O(1) médio * amortizado em array dinâmico; pode haver realocação ocasional ** considerando operação no início/topo/fim com ponteiros adequados *** se precisar localizar a posição antes, vira O(n)Questões-modelo (escolha da estrutura adequada)
Questão 1
Um módulo de atendimento ao público precisa chamar senhas estritamente na ordem de chegada. Qual estrutura é mais adequada?
- A) Pilha
- B) Fila
- C) Mapa
- D) Array
Gabarito: B. A ordem de atendimento é FIFO.
Questão 2
Um sistema precisa permitir “desfazer” a última alteração feita em uma minuta, repetidamente, sempre revertendo a ação mais recente. Qual estrutura é mais adequada?
- A) Fila
- B) Pilha
- C) Mapa
- D) Lista encadeada
Gabarito: B. Desfazer é LIFO.
Questão 3
Deseja-se consultar rapidamente um processo a partir do seu número (chave única), com muitas consultas e inserções ocasionais. Qual estrutura tende a ser mais adequada?
- A) Array
- B) Lista encadeada
- C) Mapa (hash)
- D) Pilha
Gabarito: C. Busca por chave em média O(1).
Questão 4
Uma rotina mantém uma coleção de itens e precisa acessar frequentemente o elemento na posição i (k-ésimo), com poucas inserções/remoções no meio. Qual estrutura é mais adequada?
- A) Array
- B) Lista encadeada
- C) Fila
- D) Mapa
Gabarito: A. Acesso por índice é O(1).
Questão 5
Considere um array com n elementos. Qual é a complexidade de inserir um novo elemento na primeira posição, deslocando os demais?
- A) O(1)
- B) O(log n)
- C) O(n)
- D) O(n log n)
Gabarito: C. É necessário deslocar n elementos no pior caso.
Questão 6
Um mapa baseado em árvore balanceada é escolhido para manter chaves em ordem (para relatórios ordenados por número). Qual complexidade típica de busca por chave?
- A) O(1)
- B) O(log n)
- C) O(n)
- D) O(n log n)
Gabarito: B. Árvores balanceadas mantêm altura O(log n).