Análise de Estruturas de Dados e Algoritmos em Python (2ª Edição)
Este livro é um clássico sobre estruturas de dados e algoritmos utilizando Python. Aborda revisão dos fundamentos do Python, análise de algoritmos (notação O grande), estruturas de dados básicas (pilha, fila, lista), recursão, busca e ordenação, algoritmos de árvores e grafos. Com listas práticas de código, ajuda os leitores a entender como implementar eficientemente diversos tipos abstratos de dados em Python.
Aulas
Visão Geral do Curso
📚 Resumo do Conteúdo
Este livro é um clássico texto sobre estruturas de dados e algoritmos usando Python. Cobertura inclui revisão básica de Python, análise de algoritmos (notação O grande), estruturas de dados básicas (pilha, fila, lista), recursão, busca e ordenação, algoritmos de árvores e grafos. Através de listas práticas de código, ajuda os leitores a compreender como implementar eficientemente diversos tipos abstratos de dados em Python.
Apenas ao dominar estruturas de dados e algoritmos é possível realmente dominar o Python.
Autor: Bradley Miller (Professor Emérito de Ciência da Computação na Luther College, EUA) e David Ranum (Engenheiro de Software Cognitivo IBM Watson)
Agradecimentos: Agradeço aos colegas Steve Hubbard por fornecer feedback extenso para a 1ª edição e novos materiais para a nova versão, bem como a colegas de todo o mundo que enviaram correções e sugestões por e-mail. Agradeço também aos funcionários Mary, Bob e outros da cafeteria Java John's em Decora, por permitir que nos tornássemos "escritores residentes" durante nossas férias. Além disso, agradeço à equipe da Franklin, Beedle & Associates (especialmente Jim Leisy e Tom Sumner) pela agradável colaboração. Por fim, agradeço especialmente às nossas esposas, Jane Miller e Brenda Ranum, cujo amor e apoio tornaram este livro uma realidade.
🎯 Objetivos de Aprendizagem
- Compreender a relação entre ciência da computação, algoritmos e programação, além de dominar os conceitos de tipos abstratos de dados (ADT) e ocultação de informações.
- Dominar o uso dos tipos de dados embutidos em Python (listas, tuplas, conjuntos, dicionários) e estruturas de controle (laços, ramificações, tratamento de exceções).
- Compreender os pilares da programação orientada a objetos em Python: definição de classes, métodos construtores, sobrecarga de operadores (como adição de frações), aplicação do algoritmo de Euclides e diferença entre igualdade profunda e superficial.
- Comparação de múltiplas soluções de algoritmos: explicar as quatro abordagens para detecção de anagramas (contagem, ordenação, força bruta, contagem de frequência) e seus respectivos tempos de complexidade.
- Análise quantitativa de desempenho em containers Python: dominar a eficiência Big O das operações principais em listas (List) e dicionários (Dict), diferenciando o desempenho de
pop()epop(i). - Capacidade de validação de desempenho: utilizar o módulo
timeitpara projetar experimentos e validar a consistência entre complexidade teórica e tempo real de execução. - Compreender e distinguir as características lógicas das estruturas lineares (pilha, fila, deque, lista).
- Implementar pilhas, filas e deques personalizados usando coleções básicas do Python (como listas).
- Aplicar pilhas no processamento de expressões (conversão de notação infixada para pós-fixa e avaliação pós-fixa) e filas na simulação de sistemas (simulação de impressora).
- Dominar os três princípios centrais da recursão: identificar e escrever funções recursivas com caso base, evolução de estado e chamada recursiva.
🔹 Lição 1: Fundamentos de Programação em Python e Abstração Orientada a Objetos
Visão Geral: Este módulo visa guiar os aprendizes da teoria fundamental da ciência da computação até a prática da programação em Python. Começamos definindo conceitos centrais de ciência da computação, algoritmos e tipos abstratos de dados (ADT), depois exploramos profundamente os tipos embutidos em Python, estruturas de controle e tratamento de exceções. Finalmente, demonstramos o poder da programação orientada a objetos (POO) na abstração de processos e dados por meio da construção da classe Fraction e da hierarquia de herança "portas lógicas".
Resultados de Aprendizagem:
- Compreender a relação entre ciência da computação, algoritmos e programação, bem como dominar os conceitos de tipos abstratos de dados (ADT) e ocultação de informações.
- Dominar o uso dos tipos de dados embutidos em Python (listas, tuplas, conjuntos, dicionários) e estruturas de controle (laços, ramificações, tratamento de exceções).
- Compreender os pilares da programação orientada a objetos em Python: definição de classes, métodos construtores, sobrecarga de operadores (como adição de frações), aplicação do algoritmo de Euclides e diferença entre igualdade profunda e superficial.
🔹 Lição 2: Análise de Algoritmos e Desempenho de Containers em Python
Visão Geral: Este módulo explora em profundidade como avaliar a eficiência de algoritmos usando a notação O grande, exemplificando com a detecção de anagramas a evolução desde O(n!) até O(n) em diferentes complexidades. Também analisa quantitativamente o desempenho das estruturas de dados principais do Python (listas e dicionários), ajudando desenvolvedores a escolherem os melhores containers e planejarem algoritmos otimizados em contextos reais.
Resultados de Aprendizagem:
- Comparação de múltiplas soluções de algoritmos: explicar as quatro abordagens para detecção de anagramas (contagem, ordenação, força bruta, contagem de frequência) e suas complexidades temporais correspondentes.
- Análise quantitativa de desempenho em containers Python: dominar a eficiência Big O das operações principais em listas (List) e dicionários (Dict), diferenciando o desempenho de
pop()epop(i). - Capacidade de validação de desempenho: utilizar o módulo
timeitpara projetar experimentos e verificar a consistência entre complexidade teórica e tempo real de execução.
🔹 Lição 3: Estruturas Lineares Básicas: Pilha, Fila e Lista Encadeada
Visão Geral: Este módulo explora profundamente quatro estruturas lineares fundamentais: pilha (Stack), fila (Queue), deque (Double-ended Queue) e lista (List). A característica central das estruturas lineares é manter uma ordem relativa entre elementos, com a principal diferença residindo nos métodos de adição e remoção. Ao implementar esses tipos abstratos de dados (ADT) em Python, os alunos aprenderão a resolver problemas algorítmicos reais usando princípios como LIFO (último a entrar, primeiro a sair) e FIFO (primeiro a entrar, primeiro a sair), como conversão de expressões, simulação de sistemas e gerenciamento de memória em listas encadeadas.
Resultados de Aprendizagem:
- Compreender e distinguir as características lógicas das estruturas lineares (pilha, fila, deque, lista).
- Implementar pilhas, filas e deques personalizados usando coleções básicas do Python (como listas).
- Aplicar pilhas no processamento de expressões (conversão de notação infixada para pós-fixa e avaliação pós-fixa) e filas na simulação de sistemas (simulação de impressora).
🔹 Lição 4: Princípios de Algoritmos Recursivos e Introdução à Programação Dinâmica
Visão Geral: Este módulo explora em profundidade os princípios centrais dos algoritmos recursivos, partindo dos três princípios fundamentais da recursão. Usando exemplos como conversão numérica, geometria fractal e resolução clássica de enigmas (Torre de Hanói e labirinto), revelamos o mecanismo subjacente da chamada recursiva — os frames da pilha. Por fim, introduzimos o conceito de programação dinâmica (Dynamic Programming), mostrando como técnicas de memorização podem resolver o problema de cálculos repetidos em recursão, resultando em uma melhoria qualitativa na eficiência do algoritmo.
Resultados de Aprendizagem:
- Dominar os três princípios centrais da recursão: identificar e escrever funções recursivas com caso base, evolução de estado e chamada recursiva.
- Compreender o mecanismo de execução subjacente: entender como a pilha de chamadas do Python (Stack Frame) gerencia variáveis locais e caminhos de retorno durante a recursão.
- Ter capacidade de modelagem de problemas complexos: aplicar recursão e backtracking para resolver problemas não lineares como Torre de Hanói e busca em labirintos.
🔹 Lição 5: Técnicas de Busca, Hashing e Algoritmos de Ordenação
Visão Geral: Este módulo se concentra nas tecnologias centrais de processamento de dados na ciência da computação: busca, hashing (hashing) e ordenação. Aborda desde buscas sequenciais até pesquisas binárias eficientes, explora em profundidade a construção de tabelas hash (Hash Tables), métodos de resolução de colisões e a implementação do tipo abstrato de dados Map (Map). Também analisa detalhadamente os algoritmos de ordenação: bolha, shell e merge, com foco em sua lógica e desempenho.
Resultados de Aprendizagem:
- Compreender e comparar os cenários de aplicação e complexidades temporais da busca sequencial versus busca binária (O(n) vs O(\log n)).
- Dominar o design de funções hash (método de dobramento, método da média quadrada) e mecanismos de resolução de colisões (sondação linear, sondação quadrática, encadeamento).
- Realizar simulações manuais e implementar em código os algoritmos de ordenação por bolha, shell e merge, entendendo a aplicação da estratégia de divisão e conquista na ordenação.
🔹 Lição 6: Estruturas de Árvore: Heap Binário, Árvore de Busca e Árvores Balanceadas (AVL)
Visão Geral: Este módulo explora em profundidade as estruturas de dados mais centrais da ciência da computação — as árvores. Começamos com termos básicos e a implementação de árvores binárias, avançando para aplicações avançadas como árvores de análise de expressões e seus métodos de percurso. Depois, estudamos duas variantes eficientes: heap binário, usado para filas de prioridade, e árvore binária de busca (BST), usada para busca eficiente. Finalmente, investigamos as árvores AVL, utilizando rotações para manter o fator de balanceamento e resolver a degradação de desempenho da BST em casos extremos.
Resultados de Aprendizagem:
- Definir com precisão os termos centrais de árvores (raiz, aresta, caminho, altura, etc.) e descrever a propriedade recursiva das árvores binárias.
- Dominar os algoritmos principais para implementar heaps binários, árvores binárias de busca e árvores AVL em Python (como inserção, remoção, rotações e reequilíbrio).
- Executar e explicar os três algoritmos de percurso de árvores, utilizando árvores de análise para processar expressões matemáticas.
🔹 Lição 7: Algoritmos de Teoria dos Grafos: Busca, Caminho Mínimo e Árvore Geradora Mínima
Visão Geral: Este módulo explora em profundidade a teoria fundamental dos grafos e sua implementação eficiente em Python. Aborda o tipo abstrato de dados de grafos (matriz de adjacência e lista de adjacência), algoritmos de busca básicos (BFS e DFS) e suas aplicações clássicas. Finalmente, avança para algoritmos em grafos ponderados: caminho mínimo (Dijkstra) e árvore geradora mínima (Prim).
Resultados de Aprendizagem:
- Compreender e comparar os dois principais métodos de representação de grafos (matriz de adjacência e lista de adjacência) quanto a desempenho e cenários de uso.
- Dominar os princípios dos algoritmos BFS (busca em largura) e DFS (busca em profundidade), resolvendo problemas de busca de caminhos e percurso completo.
- Aplicar algoritmos de grafos para resolver problemas complexos de dependência lógica (ordenamento topológico) e conectividade de rede (componentes fortemente conexos, árvore geradora mínima).
🔹 Lição 8: Revisão Temática: Criptografia RSA, Listas de Saltos e Quantização com Árvores Octa
Visão Geral: Este módulo explora a transição de estruturas de dados básicas para algoritmos complexos na ciência da computação. Aborda a implementação interna da lista dinâmica (ArrayList) em Python e sua análise amortizada, algoritmos recursivos da teoria dos números que suportam criptografia RSA, a construção de listas de saltos para melhorar a eficiência de buscas em dicionários, e o princípio da quantização de cores em imagens digitais usando árvores octa.
Resultados de Aprendizagem:
- Compreender a disposição de memória de ArrayList e a derivação matemática da análise amortizada (Amortized Analysis).
- Dominar os princípios matemáticos centrais da criptografia RSA, incluindo o teorema de congruência, potências modulares e o algoritmo de Euclides estendido.
- Descrever a estrutura em níveis de listas de saltos, seu processo de construção probabilístico e sua eficiência de busca O(\log n).