Revisão de Estruturas de Dados
---
id: 67f39dc7129b092b27099d8c
title: Revisão de Estruturas de Dados
challengeType: 31
dashedName: review-data-structures
---
# --description--
Algoritmos e Notação Big O
- Algoritmos: Um conjunto de instruções inequívocas para resolver um problema ou executar uma tarefa. Algoritmos devem terminar em um número finito de etapas e cada etapa deve ser precisa e inequívoca.
- Notação Big O: Descreve o desempenho no pior caso, ou taxa de crescimento, de um algoritmo conforme o tamanho da entrada aumenta. Ela foca em como o uso de recursos cresce com o tamanho da entrada, ignorando fatores constantes e termos de ordem inferior.
Complexidades de Tempo Comuns
- O(1) - Tempo Constante: O algoritmo leva a mesma quantidade de tempo independentemente do tamanho da entrada.
def check_even_or_odd(number):
if number % 2 == 0:
return 'Even'
else:
return 'Odd'
- O(log n) - Tempo Logarítmico: O tempo aumenta lentamente conforme a entrada cresce. Comum em algoritmos que reduzem repetidamente o tamanho do problema por uma fração (como
Binary Search). - O(n) - Tempo Linear: O tempo de execução aumenta proporcionalmente ao tamanho da entrada.
for grade in grades:
print(grade)
- O(n log n) - Tempo Log-Linear: Complexidade de tempo comum de algoritmos de ordenação eficientes como Merge Sort e Quick Sort.
- O(n²) - Tempo Quadrático: O tempo de execução aumenta quadraticamente. Frequentemente visto em loops aninhados.
for i in range(n):
for j in range(n):
print("Hello, World!")
Complexidade de Espaço
- O(1) - Espaço Constante: Algoritmo usa a mesma quantidade de memória independentemente do tamanho da entrada.
- O(n) - Espaço Linear: O uso de memória cresce proporcionalmente ao tamanho da entrada.
- O(n²) - Espaço Quadrático: O uso de memória cresce quadraticamente com o tamanho da entrada.
Técnicas de Resolução de Problemas
- Entendendo o Problema: Leia a declaração do problema várias vezes. Identifique a entrada, a saída esperada e como transformar a entrada na saída.
- Pseudocódigo: Descrição em alto nível da lógica do algoritmo que é independente de linguagem. Usa linguagem escrita comum misturada com construções de programação como
IF,ELSE,FOReWHILE.
GET original_string
SET reversed_string = ""
FOR EACH character IN original_string:
ADD character TO THE BEGINNING OF reversed_string
DISPLAY reversed_string
- Casos de Borda: Entradas específicas e válidas que ocorrem nos limites do que um algoritmo deve tratar. Sempre considere e teste casos de borda.
Arrays
- Arrays Estáticos: Têm um tamanho fixo determinado na inicialização. Elementos armazenados em locais de memória adjacentes. O tamanho não pode ser alterado durante a execução do programa.
- Arrays Dinâmicos: Podem crescer ou encolher automaticamente durante a execução do programa. Gerencie o redimensionamento por meio da cópia automática para arrays maiores quando necessário.
Listas Python (Arrays Dinâmicos)
numbers = [3, 4, 5, 6]
# Access elements
numbers[0] # 3
# Update elements
numbers[2] = 16
# Add elements
numbers.append(7)
numbers.insert(3, 15) # Insert at specific index
# Remove elements
numbers.pop(2) # Remove at specific index
numbers.pop() # Remove last element
Complexidades de Tempo para Arrays Dinâmicos
- Acesso: O(1)
- Inserir no final: O(1) em média, O(n) quando for necessário redimensionar
- Inserir no meio: O(n)
- Delete: O(n) para meio, O(1) para fim
Pilhas
- Pilhas: estrutura de dados Last-In, First-Out (LIFO). Elementos adicionados e removidos apenas do topo.
- Operação Push: Adicionando um elemento ao topo da pilha. Complexidade de tempo: O(1).
- Operação Pop: Removendo um elemento do topo da pilha. Complexidade de tempo: O(1).
# Using Python list as stack
stack = []
# Push operations
stack.append(1)
stack.append(2)
stack.append(3)
# Pop operations
top_element = stack.pop() # Returns 3
Filas
- Filas: estrutura de dados First-In, First-Out (FIFO). Elementos adicionados na parte de trás e removidos da frente.
- Operação Enqueue: Adicionando um elemento ao final da fila. Complexidade de tempo: O(1).
- Operação Dequeue: Removendo um elemento da frente da fila. Complexidade de tempo: O(1).
from collections import deque
# Using deque for efficient queue operations
queue = deque()
# Enqueue operations
queue.append(1)
queue.append(2)
queue.append(3)
# Dequeue operations
first_element = queue.popleft() # Returns 1
Listas Ligadas
- Listas Ligadas: Estrutura de dados linear onde cada nó contém dados e uma referência para o próximo nó. Os nós estão conectados como uma corrente.
Listas Ligadas Simples
- Estrutura: Cada nó possui dados e uma referência para o próximo nó.
- Travessia: Só pode mover-se para frente da cabeça até a cauda.
- Head Node: Primeiro nó na lista, geralmente o único nó acessível diretamente.
- Nó Final: Último nó na lista, aponta para
None.
Operações e Complexidades de Tempo
- Inserir no início: O(1)
- Inserir no final: O(n) - deve percorrer até o final
- Inserir no meio: O(n) - deve percorrer até a posição
- Excluir do início: O(1)
- Excluir do final: O(n) - é necessário percorrer para encontrar o nó anterior
- Excluir do meio: O(n) - é necessário percorrer para encontrar o nó
Listas Duplamente Ligadas
- Estrutura: Cada nó possui dados e duas referências: próximo nó e nó anterior.
- Travessia: Pode se mover em ambas as direções.
- Memória: Requer mais memória do que listas simplesmente encadeadas devido à referência extra.
Hash Maps e Sets
Mapas e Hash Maps
- Map (Abstract Data Type): Gerencia coleções de pares chave-valor. Cada chave deve ser única, mas os valores podem ser repetidos.
- Hash Map: Implementação concreta do ADT map usando técnica de hashing. Usa função hash para gerar valores hash para as chaves, que determinam o local de armazenamento no array subjacente.
Dicionários Python (Hash Maps)
# Creating dictionaries
my_dictionary = {
"A": 1,
"B": 2,
"C": 3
}
# Alternative creation
my_dictionary = dict(A=1, B=2, C=3)
# Access and modify
value = my_dictionary["A"] # 1
my_dictionary["A"] = 4 # Update value
del my_dictionary["A"] # Remove key-value pair
# Check membership
"C" in my_dictionary
# Get keys, values, items
my_dictionary.keys()
my_dictionary.values()
my_dictionary.items()
Complexidades de Tempo para Hash Maps
- Caso médio: O(1) para insert, get, delete
- Pior caso: O(n) quando muitas colisões de hash ocorrem
Conjuntos
- Conjuntos: Coleções não ordenadas de elementos únicos. Não são permitidos duplicados e nenhuma ordem específica é mantida.
- Apenas Elementos Imutáveis: Conjuntos só podem conter tipos de dados imutáveis (números, strings, tuplas) porque os valores de hash devem permanecer constantes.
# Creating sets
numbers = {1, 2, 3, 4}
empty_set = set() # Must use set(), not {}
# Add and remove elements
numbers.add(5)
numbers.remove(4) # Raises KeyError if not found
numbers.discard(4) # No error if not found
# Set operations
set_a = {1, 2, 3, 4}
set_b = {2, 3, 4, 5, 6}
# Union, intersection, difference, symmetric difference
set_a.union(set_b) # or set_a | set_b
set_a.intersection(set_b) # or set_a & set_b
set_a.difference(set_b) # or set_a - set_b
set_a.symmetric_difference(set_b) # or set_a ^ set_b
# Subset and superset checks
set_a.issubset(set_b)
set_a.issuperset(set_b)
set_a.isdisjoint(set_b)
# Membership testing
5 in numbers
Complexidades de Tempo para Conjuntos
- Caso médio: O(1) para add, remove e membership testing
- Pior caso: O(n) devido a colisões de hash
Colisões de Hash
- Colisão de Hash: Ocorre quando duas chaves diferentes produzem o mesmo valor de hash.
- Estratégias de Resolução de Colisões:
- Encadeamento: Cada índice do array aponta para uma lista encadeada que armazena todos os elementos com o mesmo valor de hash
- Open Addressing: Procure pelo próximo índice disponível usando uma sequência predefinida
Quando Usar Cada Estrutura de Dados
- Listas: Quando você precisa de acesso ordenado, indexado e não sabe o tamanho antecipadamente
- Pilhas: Para operações LIFO (funcionalidade de desfazer, avaliação de expressões, retrocesso)
- Filas: Para operações FIFO (agendamento de tarefas, busca em largura)
- Listas Ligadas: Quando inserções/remoções frequentes no início, tamanho desconhecido, sem necessidade de acesso aleatório
- Hash Maps: Para buscas rápidas de chave-valor, contagem de ocorrências e cache
- Conjuntos: Para verificação de unicidade, operações matemáticas de conjunto, remoção de duplicatas