Buscar

UNIMAR EAD - Livro completo Estrutura de dados

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 124 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 124 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 124 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

ESTRUTURA DE DADOS
Prof. Me. VALDIR AMANCIO PEREIRA JUNIOR
Reitor
Márcio Mesquita Serva
Vice-reitora
Profª. Regina Lúcia Ottaiano Losasso Serva
Pró-Reitor Acadêmico
Prof. José Roberto Marques de Castro
Pró-reitora de Pesquisa, Pós-graduação e Ação Comunitária
Profª. Drª. Fernanda Mesquita Serva
Pró-reitor Administrativo
Marco Antonio Teixeira
Direção do Núcleo de Educação a Distância
Paulo Pardo
Coordenadora Pedagógica do Curso
Ana Lívia Cazane
Designer Educacional
Juliana Spadoto
Edição de Arte, Diagramação, Design Gráfico
B42 Design
*Todos os gráficos, tabelas e esquemas são creditados à autoria, salvo quando indicada a referência. Informamos
que é de inteira responsabilidade da autoria a emissão de conceitos.
Nenhuma parte desta publicação poderá ser reproduzida por qualquer meio ou forma sem autorização. A 
violação dos direitos autorais é crime estabelecido pela Lei n.º 9.610/98 e punido pelo artigo 184 do Código Penal.
Universidade de Marília 
Avenida Hygino Muzzy Filho, 1001 
CEP 17.525–902- Marília-SP
Imagens, ícones e capa: ©envato, ©pexels, ©pixabay, ©Twenty20 e ©wikimedia
G915b Sobrenome, Nome autor
Titulo Disciplina [livro eletrônico] / Nome completo autor. - 
Marília: Unimar, 2020.
PDF (XXX p.) : il. color.
ISBN XXX-XX-XXXXX-XX-X
1. palavra 2. palavra 3. palavra 4. palavra 5. palavra 6.
palavra 7. palavra 8. palavra I. Título.
CDD – 610.6952017
Introdução
O objetivo dos conteúdos sobre estruturas de dados é compreender como podemos
lidar com dados dentro dos modelos, técnicas e tecnologias relacionadas à
programação de computadores, especificamente com a linguagem de Programação de
programação Python.
Faremos desde uma revisão sobre o Python e suas estruturas básicas para podermos
lidar melhor com os dados, como entrada e saída de dados, estruturas condicionais,
estruturas de controle, além, é claro, de estudar os tipos de dados que podemos
utilizar ou até mesmo criar, como é o caso dos tipos de dados abstratos que vão
proporcionar flexibilidade e poder às técnicas e estruturas de dados que vamos
aprender.
Outros objetivos da disciplina são entender coleções de dados, desde as nativas da
linguagem Python até as coleções que podemos criar seguindo as diretrizes das
diversas estruturas de dados como listas, listas encadeadas e listas ordenadas, pilhas,
filas, matrizes e deques. Estudaremos também técnicas como a recursividade,
buscando entender melhor como podemos melhorar as soluções com mais poder e
elegância em nossos algoritmos, assim como métodos e busca e ordenação de dados,
que desempenham um papel impar na solução e otimização de algoritmos, e no final,
mas não menos importante, vamos estudar sobre a estrutura de árvores de dados. 
3
005 Aula 01:
025 Aula 02:
032 Aula 03:
042 Aula 04:
047 Aula 05:
055 Aula 06:
064 Aula 07:
070 Aula 08:
076 Aula 09:
081 Aula 10:
087 Aula 11:
093 Aula 12:
098 Aula 13:
105 Aula 14:
109 Aula 15:
114 Aula 16:
Introdução ao Python e Estruturas Básicas 
Tipos de Dados: Primitivos e Abstratos 
Coleções de Dados em Python 
Listas Lineares 
Listas Lineares Desordenadas 
Listas Lineares Ordenadas 
Pilhas 
Filas 
Deque 
Matrizes 
Recursividade 
Métodos de Ordenação I 
Métodos de Ordenação II 
Métodos de Busca: Sequencial 
Métodos de Busca: Binária 
Árvore
01
Introdução ao Python 
e Estruturas Básicas
A Linguagem de Programação
Python
A linguagem de programação Python teve sua origem próxima do início da década de
1990 e foi idealizada pelo matemático Guido Van Rossum. O Python foi elaborado
como uma linguagem de scripts, inicialmente para o sistema operacional Amoeba, e
entrou como uma evolução de outra linguagem de programação que era voltada para
físicos, engenheiros e outras profissões ligadas à matemática ou que houvesse
necessidade de processamento de dados, a linguagem ABC (SILVA, 2018).
Uma curiosidade sobre o Python é que seu idealizador deu este nome para a
linguagem, pois gostava muito do grupo de comédia britânico Monty Python. Isto o
levou a ideia de criar uma linguagem que possibilitasse o aprendizado de
programação mais simples e leve, como eram os filmes e programas humorísticos do
grupo. Outra curiosidade é que o criador queria evitar que a linguagem fosse
associada à cobra píton, porém, em 1996 a editora O’Reilly, com a autorização de Van
Rossum, publicou o livro Programming Python, que levava uma cobra píton (python, em
inglês) na capa de seu primeiro livro de programação Python. Desde então, o Python é
associado diretamente ao réptil em questão. 
Capa do livro Programming Python
6
O grupo britânico de humor Monty Phyton no filme “Em Busca do Cálice Sagrado”, de
1975
Fonte: Disponível aqui
O Python foi idealizado para proporcionar uma maior facilidade de ensino da
programação, possuindo assim uma menor curva de aprendizagem para profissionais
de outras linguagens e principalmente leigos, contando para isso com uma ótima
legibilidade, o que possibilita o desenvolvimento de software através de um código de
fácil leitura e compreensão, proporcionando uma manutenção no software
igualmente fácil e rápido quanto à sua criação (PYSCIENCE-BRASIL, 2019).
As principais características do Python são:
Linguagem de programação de alto nível.
Gratuita e Open Source.
Orientada a objetos.
Sintaxe simples, limpa, legível e elegante. 
Outros pontos importantes sobre o Python a serem ressaltados são que a utilização
de caracteres especiais é bem reduzida, fazendo assim com que o código escrito se
aproxime muito da sintaxe de um código escrito em uma linguagem estruturada
7
https://br.ign.com/monty-python/79491/news/terry-jones-fundador-de-monty-python-morre-aos-77-anos
como um pseudocódigo ou até mesmo do Português ou Inglês. É uma linguagem de
desenvolvimento e execução multiplataforma, ou seja, é possível trabalhar em
diversos sistemas operacionais e arquiteturas diferentes (SILVA, 2018).
O Python ainda conta com uma vasta biblioteca de classes, método e funções que
podem ser utilizados. Um dos fatores mais importantes e que afeta diretamente o
momento de desenvolvimento com Python é que a linguagem não utiliza caracteres
especiais para definir os blocos de código, e a estruturação dos blocos de código é
totalmente feita por meio de endentação (PYSCIENCE-BRASIL, 2019).
Hoje, o Python já está presente nativamente em diversos sistemas operacionais,
principalmente em distribuições Linux, como Ubuntu, Debian, Fedora e também em
sistemas OS X. Além de ser adotada de soluções de diversas empresas mundialmente
conhecidas tais como Google, YouTube, Disney, Globo.com e até mesmo a Nasa.
Acesse o link: Disponível aqui
No site oficial do Python, é possível ter acesso a diversos guias para
iniciantes em programação, detalhes sobre a linguagem, documentação,
informação sobre eventos e diversas outras informações.
Instalação e Ambiente
Como visto anteriormente, a linguagem Python é multiplataforma, ou seja, pode ser
desenvolvida e aplicada em diversos sistemas operacionais. Assim, é possível ser feita
sua instalação em diversos ambientes como Windows, distribuições Linux e OS X.
Hoje, existem variações do Python quer permitem ser executadas em sistemas
embarcados, ampliando a capacidade de aplicações da linguagem.
8
http://www.python.org/
Imagem 3 – Página de download do Python.
Fonte: Disponível aqui
A instalação do Python vai variar conforme o sistema operacional, e quando se trata
do Linux e OS X, a instalação é feita por meio de comandos através do terminal, o
bash. Quando se trata do Windows, conta com o auxílio de um instalador com
interface gráfica que guia os passos das instalações.
Para acesso à documentação, instruções de instalação e o download do instalador,
basta acessar o site oficial da linguagem e procurar pelo link de download ou acessar
diretamente: https://www.python.org/downloads/. Ao acessar a página, é possível ver
qual a última versão disponível para download e quais sistemas operacionais é
possível fazer a instalação (como demonstrada a Imagem3).
Ainda na página de download, é disponibilizada uma tabela com o histórico de
versões do Python, sua data de lançamento e até quando tem suporte, fator relevante
ao decidir qual versão irá aplicar em um projeto, sempre dando preferência para a
última versão (“latest version”), mas que atenda às necessidades das dependências do
projeto. A Imagem 4 traz um exemplo de tabela de versão, com data de lançamento e
até quando a versão do Python tem suporte.
Importante notar que o todo o site oficial da linguagem é em inglês, porém, é de fácil
compreensão, e você ainda pode utilizar ferramentas e plug-ins para traduzir o
conteúdo.
9
https://www.python.org/downloads/
https://www.python.org/downloads/
Imagem 4 – Exemplo de tabela de versões do Python.
Fonte: Disponível aqui
Windows Linux OS X
Para não errar na hora de instalar o Python e começar a desenvolver, existe
uma comunidade brasileira da linguagem que desenvolveu um passo a
passo bem detalhado para Windows, Linux e OS X. Além de dar dicas de
eventos, algumas páginas com tutoriais, wikis e dicas de desenvolvimento.
Para conferir a página de instalação:
Com o seu Python já instalado e devidamente configurado, também é necessária uma
IDE (Integrated Development Environment ou Ambiente de Desenvolvimento Integrado)
que permite a você escrever os algoritmos em Python e também realizar sua
execução e testes necessários. Existe uma gama enorme de opções de IDEs e
ferramentas para a linguagem, entre gratuitas pagas, open source e proprietárias.
Algumas oferecem um ambiente robusto, possibilitando até mesmo a gestão de
dependências e bancos de dados, enquanto outras oferecem apenas o editor de
código e algumas facilidades (SILVA, 2018).
10
https://www.python.org/downloads/
https://python.org.br/instalacao-windows/
https://python.org.br/instalacao-linux/
https://python.org.br/instalacao-mac/
Dentre as principais, pode-se citar: IDLE, PyCharm, PyCharm Community, Sublime,
Atom, Visual Studio Code e Vim. O PyCharm e PyCharm Community (versão gratuita)
são os mais robustos e que oferecem mais possibilidades de ferramentas
complementares, porém, em todos é possível fazer o principal: escrever e alterar
algoritmos.
Você pode encontrar mais detalhes de cada uma dessas IDEs e outras com mais
detalhes e os respectivos links para download na página da comunidade Python
Brasil: https://python.org.br/ferramentas/. Com o Python instalado e o ambiente
pronto para as primeiras linhas de código, vamos começar a entender como o Python
lida com os dados, e depois entender e construir estruturas de dados.
Estruturas do Python
Nesta seção, vamos ver as principais estruturas do Python que são capazes de
manipular dados, definindo fluxos de execução e controle, passando pelos
operadores aritméticos, entrada e saída, comandos condicionais e iterativos.
Atribuição e Operadores Aritméticos
Operadores são símbolos e caracteres especiais utilizados para determinadas ações
sobre os dados de um programa, em que tais dados estão armazenados em variáveis,
como nas demais linguagens de programação. O primeiro operador e o mais simples
da linguagem Python é o operador de atribuição, que atua diretamente para atribuir
algum valor para determinada variável. O símbolo utilizado para esse operador nos
algoritmo é o “igual” ( = ). Vale o destaque que o operador = sobrescreve informações,
ou seja, ele apaga o que já existe dentro da variável e escreve o novo dado atribuído
(PERKOVIC, 2016).
E lembre-se sempre da sintaxe básica de atribuição, variável que receberá o valor à
esquerda do operador e o valor à direita do operador, como demonstrado na Imagem
5. 
11
https://python.org.br/ferramentas/
Imagem 5 – Sintaxe da operação de atribuição.
Fonte: Próprio autor.
Referente à sintaxe da operação de atribuição, a parte que se refere ao valor que será
armazenado pode ser um dado constante ou fixo, mas também pode ser um dado
resultante de uma operação, como, por exemplo, as operações aritméticas. Dentro do
Python existem quatro operadores aritméticos básicos: soma, subtração,
multiplicação e divisão, que são representados pelos símbolos: +, -, * e /,
respectivamente (MENEZES, 2019).
Atenção ao uso de operadores aritméticos: eles seguem as mesmas regras
da matemática, inclusive o uso de parênteses e a ordem de interpretação.
A Imagem 6 a seguir traz exemplos dos operadores aritméticos aplicados com Python
e já utilizando o operador de atribuição, ou seja, o valor é calculado e então
armazenado em uma variável. Para exibir o valor resultando da operação aritmética e
que está na variável, é utilizado o comando print, que será apresentado na próxima
seção e se trata de um comando de saída.
12
Imagem 6 – Exemplo de operadores aritméticos básicos com Python
Fonte: autor.
>>> soma = 1 + 2
>>> print(soma)
3
>>> subtracao = 10 - 4
>>> print(subtracao)
6
>>> multiplicacao = 8 * 3
>>> print(multiplicacao)
24
>>> divisao = 15/2
>>> print(divisao)
7.5
Existem ainda alguns operadores especiais como de potenciação, módulo ou resto e
parte inteira da divisão, utilizando-se os seguintes símbolos: potenciação (**), módulo
(%) e parte inteira da divisão (//). A Imagem 7 traz alguns exemplos da aplicação
destes operadores especiais.
13
Imagem 7 – Exemplo de operadores aritméticos especiais com Python.
Fonte: autor.
>>> potencia = 2**3
>>> print(potencia)
8
>>> resto = 10 % 3
>>> print(resto)
1
>>> resto1 = 10 % 2
>>> print(resto1)
0
>>> parteInteira = 15 // 2
>>> print(parteInteira)
7
Comandos de Entrada e Saída
Comando de saída de dados
Uma parte importante quando lidamos com todas as linguagens de programação é a
forma como acontece a interação entre o usuário e o computador, ou seja, uma
linguagem deve ser capaz de conter comandos que possam receber e apresentar
dados e resultados ao usuário. Isto ocorre através de comandos de entrada e saída.
No Python, tais ações são realizadas pelos comandos print (saída) e input (entrada).
Nesta seção, ambos serão apresentados, junto com detalhes e exemplos (SILVA,
2018).
14
Imagem 8 – Exemplo com o comando print com “Hello World”.
O comando print() responsável pela saída de dados do algoritmo desenvolvido em
Python é um método padrão da linguagem, e conta com alguns recursos para
representar as informações e dados. Esta função imprime mensagens específicas em
uma saída padrão como, por exemplo, o console ou terminal, tela do computador e
celular. A saída ou mensagem apresentada pode ser uma string (conjunto de
caracteres) ou outros objetos, como variáveis e constantes (PERKOVIC, 2016).
A sintaxe do print() é:
print(objects, sep=separator, end=end, file=sys.stdout, flush=False)
Em um primeiro momento, pode parecer algo complexo por causa dos parâmetros
padrões, porém, eles fazem parte da construção do método e serão aplicados em
alguns momentos, apenas quando necessários.
Fique atento! A partir da versão do Python 3, no comando print() é
obrigatório o uso de parênteses.
As Imagens 8, 9 e 10 trazem exemplos do uso do comando print() e seus parâmetros e
já demonstra como concatenar valores de variáveis com string. Lembrando que
concatenar é a junção de duas ou mais strings, criando uma única mensagem a partir
de vários elementos. Assim, fique atento ao tipo do dado que está utilizando. No
Python, é possível concatenar strings, variáveis, constantes e alguns objetos, entre
outros.
>>> print('Hello World!')
Hello World!
Fonte: autor.
15
Imagem 9 – Exemplo com print e concatenação.
Fonte: autor.
Imagem 10 – Exemplo com print e dados fixos.
Fonte: autor.
>>> preco = 4.50
>>> quanitade = 3
>>> total = preco * quantidade
>>> print('Total da compra: $R$', total, ' a vista')
Total da compra: R$13.50 a vista
>>> nome = "Maria"
>>> idade = 19
>>> print('Olá ', nome, ', você tem ', idade, ' anos')
Olá Maria, você tem 19 anos
Comando de Entrada de Dados
Junto à saída de dados processados, a entrada de dados é igualmente importante,
principalmente para garantir a interação do algoritmo e softwarecom o usuário.
Quando se refere à entrada de dados, podemos pensar em diversos métodos de
entrada, e qualquer interação com o dispositivo pode ser considerada uma entrada:
teclado, mouse, tela sensíveis ao toque e até mesmo gestos ou movimentos
(MENEZES, 2019).
16
Na linguagem Python, aplica-se a função input(), comando que permite ler dados a
partir de uma entrada padrão. Para as soluções desta disciplina, será o teclado, pois
os algoritmos serão executados via terminal de comandos. Ao ser executado pelo
fluxo do algoritmo, o input bloqueia o fluxo de execução padrão do algoritmo e
aguarda até que o usuário digite um valor no terminal ou local que está sendo
executado. Por padrão, o valor lido é armazenado em uma variável e será uma string
(PERKOVIC, 2016).
A sintaxe do input() é:
variavel = input(prompt)
O parâmetro é opcional e imprime uma mensagem (string) na tela.
As Imagens 11 e 12 trazem exemplos da aplicação do comando input(), solicitando que
o usuário informe alguns dados – lembrando que o terminal ficará travado (fluxo
interrompido) até que seja pressionada a tecla “Enter”, então, o conteúdo é
armazenado na variável informada, e depois disso o programa segue normalmente a
execução.
A partir desse momento, vamos construir nossos algoritmos em um editor
de código de sua preferência e então executando o código via terminal para
executar o seu código salve em um arquivo com a extensão .py. Então,
navegue até o diretório em que foi salvo e execute o comando conforme a
versão.
Python 3: 
python3 nome_do_arquivo.py
Python 2: 
python nome_do_arquivo.py
Todos os exemplos desenvolvidos neste material serão com o Python 3.
17
Imagem 11 – Exemplo com input com uma variável.
Fonte: autor.
Imagem 12 – Exemplo com input com duas variáveis.
Fonte: autor.
Imagem 13 – Exemplo com input com casting.
Fonte: autor.
nome = input("Informe o seu nome: ")
print('Olá ' + nome + ', tudo bem?')
nome = input("Informe o seu nome: ")
sobrenome = input("Informe o seu sobrenome: ")
print('Olá ' + nome + ' ' + sobrenome +', tudo bem?')
Sabemos que o valor padrão lido e armazenado pela função input() é sempre uma
string, porém, isso pode gerar diversos problemas, pois não existe apenas um tipo de
dado, mas existem dados que são inteiros, float, booleanos e outros. O Python traz
uma forma de solucionar este problema com a conversão de tipos de dados ou
casting. Para fazer o casting, existem funções para cada tipo de dado: usar int() faz a
conversão para inteiro, float() faz a conversão para decimal com vírgula e str() faz
conversão para string (PERKOVIC, 2016).
Para fazer casting de um input, basta usar a função desejada antes do comando input,
e a Imagem 13 traz um exemplo de casting para inteiro.
distancia = int(input("Informe a distância em metros: "))
print(distancia)
18
Imagem 14 – Exemplos de casting
Fonte: autor.
Fique atento ao fazer o casting para inteiro ou float, pois para concatenas no
print é necessário utilizar a função str() pois usar o símbolo “+” para
concatenar será confundida com a operação aritmética de soma.
A Imagem 14 traz um exemplo de casting em que também é feita a concatenação de
diferentes tipos de dados.
nome = input("Inform seu nome: ")
#faz casting de string para int, pois idade é inteiro
idade = int(input("Informe sua idade: "))
#faz casting de string para float, pois altura é ponto flutuante
altura = float(input("Informe sua altura(metros): "))
print('Olá ' + nome)
#faz casting de int e float para string
print('Você tem ' + str(idade) + ' anos')
print('E sua é ' + str(altura) + ' metros.')
19
Imagem 15 – Estrutura do comando if simples
Fonte: autor.
Comandos Condicionais
Outra estrutura essencial, assim como em outras linguagens de programação, são os
comandos condicionais. Tais comandos permitem selecionar partes do nosso código
que serão executadas ou não, dependendo de testes e condições criadas. Por
exemplo, restringir um acesso ao software conforme a idade do usuário, se ele tiver
mais de 18 anos pode acessar, caso contrário, seu acesso é bloqueado (MENEZES,
2019).
Seguindo a linha de outras linguagens os comandos em Python são escritos em inglês,
logo os comandos “se” e “senão”, são escritos como “if” e “else” respectivamente. Com
o uso desses comandos no Python podemos facilmente definir quais blocos de código
serão executados, alterando o fluxo de processamento (SILVA, 2018).
Ainda existe o comando elif, que é justamente o “senão se” que permite criar uma
estrutura composta para testar mais condições em uma única estrutura. As imagens
15 e 16 trazem as possíveis sintaxes do Python para o if simples e composto.
if condição lógica:
   #bloco de código
   #esse bloco sére executado quando a
   #confição for verdadeira
else:
   #bloco de código
   #esse bloco sére executado quando a
   #confição for falsa
20
Imagem 16 – Estrutura do comando if composto
Fonte: autor.
if condição lógica 1:
   #bloco de código
   #esse bloco sére executado quando a
   #confição for verdadeira
elif condição lógica 2:
   #bloco de código
   #esse bloco sére executado quando a
   #segunda confição for verdadeira
else:
   #bloco de código
   #esse bloco sére executado quando
   #nenhumadas confições for verdadeira
21
Imagem 17 – Solução com if para definir faixa etária
Fonte: autor.
Um cenário real que podemos pensar para treinar a lógica com comando
condicionais é definir a faixa etária de pessoas conforme idade – lembrando
que a faixa etária pode variar conforme o domínio. A Imagem 17 traz um
exemplo de uma possível solução para esse cenário, e vale ressaltar que a
lógica da solução pode variar de pessoa para pessoa, mas existem boas
práticas.
idade = int(input("Informe a idade: "))
#definir faixa etária
if idade >= 60:
   print("Idoso")
elif idade >= 20:
   print("Adulto")
elif idade >= 13:
   print("Jovem")
else:
   print("Criança")
22
Imagem 18 – Solução com if para definir faixa etária.
Fonte: autor.
Comandos Iterativos
Além dos comandos condicionais, entrada e saída, operadores lógicos e aritméticos,
podemos ainda criar estrutura iterativas em nossos algoritmos com Python, tais
estruturas permitem controlar a forma de execução de alguns blocos de código,
conseguindo controlar quantas vezes um bloco será executado, ou seja, uma
repetição ou loop (MENEZES, 2019).
Dentro da linguagem Python, existem dois principais comandos que podemos
trabalhar para criar uma estrutura de repetição controlada, conseguindo assim fazer
repetir diversas vezes um único bloco de código conforme uma condição definida: o
comando while e o comando for. A Imagem 18 demonstra a sintaxe e estrutura para
construir o while e o for, lembrando que são estruturas separadas (PERKOVIC, 2016).
Aplicando ambos os comandos de iteração, eles podem ser combinados ou
agrupados, gerando assim uma estrutura com diferentes fluxos de execução, por
exemplo, um while dentro de outro while ou um for. Porém essa é uma prática que
devemos ter cuidado, uma vez que pode gerar loops infinitos e travar a execução de
uma máquina ou servidor, gerando imprevistos e custos desnecessários.
while condição:
   #bloco de código
for variável in objeto iterável:
   #bloco de código
23
Imagem 19 – Solução com if para definir faixa etária.
Fonte: autor.
Vamos imaginar uma lista com quatro alunos de uma turma de inglês, e
estes alunos precisam saber qual é a sua nota final baseado em três notas,
prova, participação e trabalho. A prova vale 5, a participação vale 4 e o
trabalho 1. Vamos criar um algoritmo com loop para calcular as notas?
A Imagem 19 traz uma possível solução ao problema, já utilizando de uma
lista em Python e também da estrutura for para repetição.
alunos = ["Vitória", "Carlos", "Renata"]
for nome in alunos:
   print("Aluno: " + nome)
   nProva = float(input("Nota da prova: "))
   nParticipacao = float(input("Nota de participação: "))
   nTrabalho = float(input("Nota do trabalho: "))
   media = (nProva * 0.5) + (nParticipacao * 0.4)+
(nTrabalho * 0.1)
   print("A nota final foi: " + str(media) + "\n")
24
Acesse os links: Disponível aqui Disponível aqui
Algumas dicas sempre importantes:
Os blocos de código são definidos por endentação
Comandos como if, else, elif, while e for sempre tem “:” antes do
próximo bloco de código
Consulte sempre a documentação do Python.
25
https://www.python.org/doc/
https://python.org.br/introducao/
02
Tipos de Dados: 
Primitivos e Abstratos
Ao começar a estudar a forma como podemos lidar, entender e manipular dados
dentro da programação de computadores, algoritmos e software, é importante
entender como os dados vão se comportar ou qual a sua natureza, já vimos que
podemos ler dados do usuário, processar de alguma forma tais dados e também
apresentar dados ao usuário (GUIMARÃES, 1984).
Porém, ai encontramos uma possível limitação que precisamos fazer a conversão de
tipo dos dados ou casting, pois o Python sempre lê dados como string e então
precisamos converter caso seja um inteiro ou float. Nesta aula, vamos compreender
um pouco melhor os diversos tipos de dados do Python e como podemos trabalhar
com eles (PERKOVIC, 2016).
Tipos de Dados Primitivos ou
Nativos
Sempre que vamos desenvolver qualquer solução com programação, pensamos em
quais iremos trabalhar e formas como podemos trabalhar tais dados, ou seja, iremos
precisar de variáveis para armazenar esses dados, como por exemplo: nome, idade,
altura, sexo, peso, data de nascimento, nacionalidade, entre diversos outros dados
(GUIMARÃES, 1984).
Porém, cada um desses dados é de um tipo diferente, logo, cada variável também tem
um único tipo. Olhando atentamente aos exemplos, como um nome é composto? Ele
contém letras em determinada sequência que lhe dão um significado, mas pode
representar a sua idade? Um texto também? Uma sequência de letras? Nesse caso o
mais recomendado para a idade é um número. Podemos ir muito além, saldo
bancário, distância de uma viagem, cores, cada cenário tem diversas variáveis.
Já sabemos então que temos diferentes tipos de dados para cada domínio, mas como
vamos trabalhar com eles? O Python é uma linguagem que respeita tais tipos, porém
não é fortemente tipada, como é o Java, ou seja, não precisamos falar qual o tipo
dessa variável, basta associar um valor e a mesma irá assumir esse tipo.
27
De forma geral, as linguagens de programação seguem alguns tipos de dados
primitivos, como inteiro, texto, real, etc. A linguagem Python segmenta seus dados em
dois grandes grupos: dados atômicos e dados coletivos, e cada um desses grupos
contém mais tipos de dados (PERKOVIC, 2016). 
Um dado atômico, independente da linguagem de programação é um dado
único, atômico está relacionado à menor unidade possível, por exemplo,
uma variável do tipo inteiro que contém apenas um único valor, é uma
variável atômica.
Já um dado coletivo, ou do tipo coletivo, faz referência direta a uma
coletânea de valores, ou seja, um agrupamento de dados em um único
espaço. Um exemplo são os vetores ou arrays, que dependendo da
linguagem, cria uma coleção de diversos dados em uma única variável,
sendo que cada dado interno pode ser de um tipo atômico diferente.
Neste momento, vamos focar nos dados atômicos primitivos, em entender os tipos de
dados e variáveis. De forma geral, existem 4 tipos primitivos de dados, porém cada
linguagem de programação pode criar variações e subdivisões desse tipos, mas de
modo geral os tipos primitivos de dados são (PERKOVIC, 2016; SZWARCFITER, 2017):
Inteiro: faz referência aos conjuntos dos números inteiros da matemática, ou
seja, valores negativos e positivos sem casa decimal.
Real: está relacionado aos valores reais da matemática, também chamados de
ponto flutuante, contemplam números negativos e positivos com casa decimal.
Lógico: são valores booleanos, podendo assumir apenas dois estados,
VERDADEIRO ou FALSE. Na computação pode ser representado por apenas um
bit, sendo o bit 1 para verdadeiro e 0 para falso.
Texto: refere-se a qualquer sequência de um ou mais caracteres utilizando os
valores do tipo “texto” entre “ ” (aspas duplas). 
28
Imagem 2 – Tipo de dados atômicos em Python e função type.
Fonte: autor.
A linguagem Python incorpora esses tipos genéricos, mas com algumas variações de
nomenclatura, assim temos os tipos: int (inteiro), float (real), string (texto) e boolean
(lógico). Como o Python não tem tipagem forte, ou seja, não consegui saber qual o
tipo da variável pela sua declaração, temos a função type() para revelar qual o tipo do
dado. Um detalhe importante, como a linguagem é orientada a objeto, os tipos de
dados são tratados como classes. A Imagem 2 traz um exemplo de variáveis e seu
tipos, aplicando a função type() (PERKOVIC, 2016).
>>> nome = "João"
>>> idade = 20
>>> saldo = 3260.89
>>> sexo = 'M'
>>> logico = True
>>> type(nome)
<class 'str'>
>>> type(idade)
<class 'int'>
>>> type(saldo)
<class 'float'>
>>> type(sexo)
<class 'str'>
>>> type(logico)
<class 'bool'>
29
Fique sempre atento ao retorno em qual tipo de dado do Python melhor se
enquadra na situação que irá resolver. Um valor de saldo de conta bancária
fica bem expresso como uma string? Ou fica melhor como float? A resposta é
com float, pois em um saldo bancário você precisa fazer operações de
crédito e débito e com um dado do tipo float você pode fazer operações
aritméticas.
Tipos de Dados Abstratos ou
Customizados
Até agora vimos os dados primitivos ou nativos, que estão intimamente ligados à
estrutura e construção de um dado, não se preocupando ao o que é dado ou sua
representação. Vimos diversos exemplos de nome, idade, altura, saldo e outros,
porém são dados isolados e que representam um único valor.
E se for necessário criar um tipo de dado mais amplo e que se adeque melhor ao
cenário que estamos programando, é necessária a aplicação do conceito de Tipos de
Dados Abstratos (TAD) que é justamente a capacidade de encapsular os tipos
primitivos e criar um tipo maior. Podemos pensar em diversos tipos de dados
abstratos, como a maioria dos objetos (SZWARCFITER, 2017; GUIMARÃES, 1984).
O TAD é criação de um bloco bem estruturado de dados e um conjunto de ações e
métodos preparados para a manipulação de tal bloco de dados. Os dados são
chamados de atributos e as operações de Interface do TAD. Tal conceito surgiu junto a
programação estruturada, mas contribuiu para o surgimento do paradigma orientado
a objetos (GUIMARÃES, 1984).
30
Por exemplo, como podemos desenvolvedor uma solução para lidar com um caixa
econômico ou ATM, cada pessoa tem sua conta e pode realizar ações, uma conta tem
saldo, mas a conta pertence a uma pessoa. Neste caso, podemos criar um tipo
abstrato “pessoa”, que pode ter diversas características tais como nome, número da
conta, data da última movimentação e, dessa forma, ainda podemos ter diversas
pessoas de maneira isolada e que podem até ter ações programadas, como realizar
um saque, depositar, solicitar comprovante, entre outras.
A implementação de tipos de dados abstratos está diretamente relacionado a lidar
com a estrutura de dados, pois fará o uso de coleções de tipos de dados primitivos.
Existem diferentes maneiras de implementar um tipo de dado abstrato, utilizando da
linguagem Python, podemos utilizar classes, dicionário e até mesmo listas para
representar e manipular os dados (SZWARCFITER, 2017; PERKOVIC, 2016).
A Imagem 3 traz o exemplo de implementação de um TAD utilizando classes com
Python que representa uma conta bancária, com atributos de tipo primitivo e algumas
ações para ver o saldo e fazer um saque, de forma bem simples, apenas para
apresentar um exemplo de construção. Essa construção permite mais flexibilidade ao
desenvolvedor e cria uma interface com o usuário para que ele não note possíveis
mudanças na estrutura de uma forma muito brusca ou que possa gerar problemas.
Pode-se observar, no final do exemplo, que existe a criação de uma variável do tipo
Conta (TAD criado) e logo em seguida é utilizado o comando type() para verificar o tipo
e o retornoé o tipo Conta, como esperado. 
31
Imagem 3 – Representação de uma estrutura de tipo de dados abstrata com
classe em Python.
Fonte: autor.
class Conta:
   saldo = 0
   numero = '00000-00'
   cliente = 1
   def total(self):
       return self.saldo
   def saque(self, valor):
       return self.saldo - valor
>>> conta1 = Conta()
>>> type(conta1)
<class '__main__.Conta'>
32
03
Coleções de Dados 
em Python
Olá a todos!
Além da possibilidade de trabalhar com dados nativos e abstratos, diversas
linguagens de programação oferecem a possibilidade de trabalhar com coleções de
dados, e uma coleção nada de mais é que um agrupamento de dados, que podem
ser do mesmo tipo ou não. Assim, conseguimos criar conjuntos ou coleções de
diversas formas, bem como uma coleção pode ser tida como uma estrutura de dados
SZWARCFITER e MARKENZON, 2017; GUIMARÃES, 1984; PERKOVIC, 2016; (MILLER e
RANUM, 2013).
Podem-se achar referências e citações de coleções como vetores, arrays, listas,
conjuntos, dicionários, entre outros, pois esse termo pode variar conforme a
linguagem de programação utilizada (SZWARCFITER e MARKENZON, 2017;
GUIMARÃES, 1984). 
34
Imagem 2 – Iteração com variável string como conjunto.
Fonte: autor.
Vimos que textos ou string são listados como tipos de dados primitivos e
atômicos, ou seja, todo o conteúdo está contido em uma variável. Porém,
como o Python trata seus tipos primitivos também como classes e uma
string é considerada um conjunto de caracteres, alguns métodos e técnicas
para lidar com conjuntos de dados pode ser aplicados em um string.
Por exemplo, é possível fazer uma iteração com loop utilizando while em
uma variável do tipo string. A Imagem 2 traz um exemplo de código fazendo
uma iteração em uma string.
texto = "paralelepipedo"
i = 0
while i < len(texto):
   print(texto[i])
   i+=1
A linguagem Python segmenta as coleções de duas formas: coleções ordenadas e
coleções não ordenadas.
Como ordenadas, são categorizadas em listas (tipo list), strings (tipo str) e tuplas (tipo
tuple). As não ordenadas são: conjuntos (tipo set) e dicionário (tipo dict) – lembrando
que toda iteração entre os elementos de uma coleção inicia na posição 0 por padrão.
35
Imagem 3 – Relação entre elementos e posições em uma coleção.
Fonte: Próprio autor.
A Imagem 3 traz uma relação entre elementos e a posição referente, relação esta que
deve ser clara para não haver erros na iteração (PERKOVIC, 2016; MILLER e RANUM,
2013).
Podemos definir assim que as posições de uma coleção são dadas pelo tamanho da
coleção -1, para descobrir o tamanho, ou número de elementos, de uma coleção
podemos utilizar a função len() do Python.
Lista
Listas em Python são coleções ordenadas de zero ou mais referências a tipos de
dados ou objetos. A estrutura para construção de uma lista em Python é
relativamente simples, cuja delimitação é feita por colchetes e os elementos são
separados por vírgulas. Uma lista pode ser heterogênea, ou seja, os dados e objetos
presentes dentro da lista podem ser de diferentes tipos ou classes. Além disso, uma
estrutura de lista pode ser atribuída em uma variável.
A Imagem 4 traz alguns comandos com listas (PERKOVIC, 2016; MILLER e RANUM,
2013). 
36
Imagem 4 – Comando com listas em Python.
Fonte: autor.
>>> [1, 2.5, 10, 5, "Teste", True]
[1, 2.5, 10, 5, "Teste", True]
>>> lista1 = [1, 2.5, 10, 5, "Teste", True]
>>> lista1
[1, 2.5, 10, 5, "Teste", True]
>>> len(lista1)
6
A Tabela 1 traz uma relação de comandos referentes ao Python e podem ser
aplicados em listas. O conceito de uma coleção que vimos e que tem a posição de 0
até o número de elementos -1 é útil aqui para aplicar o fatiamento ou indexação.
37
Tabela 1 – Operações para Listas em Python
Fonte: Próprio autor.
Operações para Listas em Python
Nome Operador Descrição
Indexação [ ] Acessa um elemento da lista
Concatenação + Combina duas listas
Repetição * Concatena N vezes a lista
Pertinência In Valida se um elemento pertence à lista
Comprimento len() Retorna o total de elementos da lista
Fatiamento [ : ] Extrai parte de uma lista
A Imagem 5 traz um exemplo de aplicação das operações com lista em Python, e a
Tabela 2 traz a relação de métodos relacionados a listas.
38
Imagem 5 – Operações com lista em Python.
Fonte: autor.
>>> lista2 = [1, 2, 3, 4, 5]
>>> lista2
[1, 2, 3, 4, 5]
>>> lista2[0]
1
>>> lista3 = [6, 7, 8]
>>> lista2 + lista3
[1, 2, 3, 4, 5, 6, 7, 8]
>>> 0 in lista2
False
>>> 1 in lista2
True
>>> lista2[0:1]
[1]
>>> lista2[1:4]
[2, 3, 4]
39
Tabela 2 – Métodos para Listas em Python
Fonte: Próprio autor.
Métodos para Listas em Python
Nome Uso Descrição
append list.append(elemento) Adiciona um novo item ao final de uma lista
insert list.insert(i, elemento)
Insere um elemento em uma posição
específica
pop list.pop()
Remove e retorna o último elemento de uma
lista
pop list.pop(i)
Remove e retorna um elemento específico
de uma lista
sort list.sort() Ordena uma lista
reverse list.reverse()
Modifica uma lista, invertendo a ordem dos
itens
del del list[i] Exclui o elemento em uma posição específica
index list.index(elemento)
Retorna o índice da primeira ocorrência de
um elemento
count list.count(elemento)
Retorna o número de ocorrências de um
elemento
remove list.remove(item)
Remove a primeira ocorrência de um
elemento
40
Imagem 6 – Operações com tupla em Python.
Fonte: autor.
Tupla
As listas se parecem em diversos fatores com as listas em Python: são coleções de
dados e permitem dados heterogêneos. Mas a grande diferença é que as tuplas são
imutáveis, ou seja, não é possível incluir ou excluir elementos presentes em uma tupla
– entretanto, é possível aplicar as operações de lista, como indexação, fatiamento ou
pertinência (PERKOVIC, 2016; MILLER e RANUM, 2013).
A construção da tupla também se aproxima das listas. Os elementos são separados
por vírgulas, mas é delimitada por parênteses. A Imagem 6 traz o exemplo de
construção de uma tupla e operações. 
>>> tupla = (1, 3, 5.2, True, "Texto")
>>> tupla
(1, 3, 5.2, True, "Texto")
>>> tupla[1]
2
>>> tupla[3]
True
>>> 5.2 in tupla
True
>>> tupla[1:3]
(3, 5.2)
41
Imagem 7 – Criação de um dicionário com Python.
Fonte: autor.
Dicionário
A estrutura de dicionário é uma coleção desordenada de elementos. A associação dos
elementos de uma lista é feita por pares associados em que cada par é composto por
uma chave e um valor. Cada chave-valor é separada por vírgulas e delimitada por
chaves. A Imagem 7 traz um exemplo de criação de um dicionário em Python,
apresentando a relação de moradores por cidade, onde a chave é o nome da cidade e
o valor o total da população (PERKOVIC, 2016; MILLER e RANUM, 2013).
>>> populacao = {"São Paulo":12180000, "Rio de Janeiro":6320000,
"Florianópolis":477798}
>>> populacao
{'São Paulo':12180000, 'Rio de Janeiro':6320000,
'Florianópolis':477798}
É possível manipular dicionários acessando os valores por meio da chave relacionada
a cada valor ou adicionar um novo elemento através de um novo par chave-valor. A
forma de acesso remete a listas e tuplas, porém, ao invés de usar a posição ou índices
do elemento que se deseja acessar, vamos utilizar o valor da chave, para adicionar um
valor também é semelhante.   A Imagem 8 traz algumas manipulações com uma
dicionário.
42
Imagem 8 – Criação de um dicionário com Python.
Fonte: autor.
>>> print(populacao['São Paulo'])
12180000
>>> populacao['Belo Horizonte'] = 1433000
>>> print(populacao)
{'São Paulo':12180000, 'Rio de Janeiro':6320000,
'Florianópolis':477798, 'Belo Horizonte' = 1433000}
>>> print(len(populacao))
4
>>> for p in populacao:
       print(p, " tem ", populacao[p], " habitantes")
São Paulo tem 12180000 habitantes
Rio de Janeiro tem 6320000 habitantes
Florianópolis tem 477798 habitantes
Belo Horizonte tem 1433000 habitantes
As Tabelas 3 e 4 trazem uma relação de operadores e métodos capazes de serem
aplicados em dicionários. É importante notar que os métodos keys, values e items
retornamobjetos que contêm o resultado de interesse.
43
Tabela 3 – Operações para Dicionários em Python
Fonte: Próprio autor.
Operações para Listas em Python
Nome Uso Descrição
Indexação  dicio[ ] Acessa um elemento do dicionário
Pertinência
chave in
dicio
Valida se um elemento pertence à lista, retorna
True ou False
Exclusão
del
dicio[chave]
Remove parte de uma lista
Tabela 4 – Métodos para Listas em Python
Fonte: Próprio autor.
Operações para Listas em Python
Nome Uso Descrição
keys dicio.keys() Retorna todas as chaves de um dicionário
values dicio.values() Retorna todos os valores de um dicionário
items dicio.items() Retorna os elementos chave-valor de um dicionário
get dicio.get(chave) Retorna o valor de uma chave ou None se não achar
get dicio.get(chave) Retorna o valor de uma chave ou alt se não achar
44
04
Listas Lineares
Olá novamente!
Nativamente, a linguagem Python já oferece formas de trabalhar coleções de dados
como as Listas, Dicionários e Tuplas, mas conforme a necessidade e complexidade da
aplicação desenvolvida, usar tais soluções não se tornam suficientes e é necessário
desenvolver uma estrutura de dados nova para suportar a representação e a
manipulação dos dados (MILLER e RANUM, 2013).
Surgem as listas ligadas ou listas encadeadas como solução para construir coleções
de dados em que cada elemento mantém um posicionamento relativo aos demais,
conseguindo navegar através de métodos pelos elementos e também garantir
determinada ordenação e controle (SZWARCFITER e MARKENZON, 2017; MILLER e
RANUM, 2013).
Ainda dentro das listas ligadas, temos as listas ordenadas e desordenadas, em que
os elementos são ou não organizados conforme são inseridos na lista, e mesmo
sendo próximas, são implementações totalmente distintas, pois agora a estrutura de
dados será criada praticamente do zero (SZWARCFITER e MARKENZON, 2017;
GUIMARÃES, 1984).
Outras estruturas de dados também lineares que ganham espaço são as pilhas, filas e
deques. Cada uma delas tem seu funcionamento muito bem definido, porém, ainda
trabalham com a relação e disposição em um ambiente em que todos os elementos
se relacionam e estão interligados. 
46
Para sempre lembrar a evolução das Listas, Tuplas e Dicionários nativos do
Python para as listas lineares que podemos implementar, é só lembrar das
ações possíveis com cada elemento, ou seja, o que um elemento de uma
lista simples pode fazer? Se ele for um tipo primitivo (texto, inteiro, float ou
booleano), não vai conseguir fazer muita coisa, apenas algumas operações.
Se ele for um tipo abstrato, como, por exemplo, uma classe, vai conseguir
executar os métodos dessa classe que ele pertence.
Porém, ao construir uma estrutura linear como as listas encadeadas, filas e
pilhas, é possível criar métodos e atributos para cada elemento,
independentemente de seu conteúdo e que vão interagir com os demais
elementos da estrutura. Um bom exemplo é a Lista Ordenada Encadeada,
que ordenada a lista assim que o elemento é inserido.
Quando falamos que os objetos e elementos de uma estrutura linear estão
interligados e se relacionam, é algo concreto, pois cada nó criado para armazenar um
valor faz referência direta aos dois elementos vizinhos, criando uma forma de
corrente e garantindo a estabilidade da estrutura (SZWARCFITER e MARKENZON,
2017; GUIMARÃES, 1984).
A Imagem 2 traz a representação gráfica do que seria um nó de um elemento em uma
estrutura linear, fazendo referência aos seus nós próximos.
47
Imagem 2 – Exemplo de nó em uma estrutura de dados linear.
Fonte: Próprio autor.
Como estas estruturas são construídas pelos próprios desenvolvedores ou
comunidade para atender as necessidades de um cenário ou domínio, também existe
a necessidade de criar métodos ou ações de controle para garantir o funcionamento
perfeito da estrutura. 
E aí surgem alguns questionamento tais como: qual é o nó final e o nó inicial? Qual a
melhor maneira de navegar entre os nós? Existe a possibilidade de fazer uma busca
entre todos os elementos? Se todos os nós têm referência, como fazer uma exclusão
sem perder a referência?
Esses questionamentos são solucionados de diferentes formas conforme a proposta
de cada uma das estruturas. Por exemplo, quanto à pilha e fila, a pilha é conhecida
como LIFO (Last-In First-Out) por causa da forma como escreve e recupera os
elementos inseridos na pilha, e a fila é conhecida como FIFO (First-In First-Out), pois já
trata o processamento dos nós de uma forma diferente, mas ainda linear.
A Imagem 3 traz uma representação genérica das estrutura de dados lineares, onde
cada elemento mantém um relacionamento com os nós próximos e tem métodos
implementados.
48
Imagem 3 – Representação de uma estrutura linear.
Fonte: Próprio autor.
As próximas aulas serão dedicas a aprofundar de forma individual cada uma das
estruturas citadas aqui, passando por conceitos e detalhes da implementação, em
que iremos desenvolver cada uma delas.
49
05
Listas Lineares 
Desordenadas
Como vimos, as estruturas de dados de listas lineares podem ser implementadas de
diversas formas conforme os objetivos e a necessidade. A primeira estrutura cuja
implementação veremos com mais detalhes são as Listas Lineares Desordenadas,
onde a sua estrutura permite a inclusão, busca e remoção de elementos e nós sem a
necessidade de acontecer a ordenação dos elementos (SZWARCFITER e MARKENZON,
2017; MILLER e RANUM, 2013; GUIMARÃES, 1984).
Assim como nas demais estruturas de listas e dicionários em Python, existem algumas
operações possíveis sobre uma lista desordenada. A Tabela 1 apresenta a relação de
operações e sua descrição (MILLER e RANUM, 2013).
Para conseguir implementar uma lista desordenada, precisamos nos lembrar do
conceito de lista ligada, onde os elementos mantêm um posicionamento relativo aos
demais elementos da lista, ou seja, um nó faz referência a outro nó. Essa estrutura
permite trabalhar com uma capacidade de memória maior, pois não necessariamente
todo o conteúdo estará alocado em um único endereço de memória. 
51
Tabela 1 – Operações para Listas Desordenadas em Python
Fonte: Próprio autor.
Operador Descrição
List() Cria uma nova lista vazia.
add(elemento) Insere um novo elemento na lista.
remove(elemento) Remove um elemento da lista e altera a referência dos nós.
search(elemento)
Procura um elemento na lista, precisa informar qual
elemento e retorna True ou False.
isEmpty() Valida se a lista está vazia, retorna True ou False.
size() Extrai parte de uma lista.
append(elemento)
Insere um novo elemento no final da lista, tornando o final
da lista.
index(elemento) Retorna a posição referente a um elemento da lista.
insert(posição,
elemento)
Insere um novo emento na lista em uma determinada
posição.
pop()
Remove e retorna o último elemento da lista, tendo que a
lista deve ter no mínimo um elemento.
pop(posição)
Remove e retorna o elemento em uma determinada
posição.
Para implementar uma estrutura de lista desordenada, precisamos de dois itens bem
definidos: o nó, que representa cada elemento que compõe a lista, e a lista
desordenada, que é justamente a coleção de nós criados que respeitam uma relação.
Tanto o nó quanto a lista têm ações e dados bem definidos, sendo que para cada nó,
52
Imagem 2 – Classe Node em Python.
Fonte: autor.
precisamos ter um valor representado por um campo de dados, ou seja, um local
onde poderemos escrever o valor do elemento. Além disso, deve ter uma referência
direta ao próximo nó da lista, enquanto a lista desordenada precisa ter uma
referência de onde é o início da lista e a implementação das operações listadas na
Tabela 1 (SZWARCFITER e MARKENZON, 2017; MILLER e RANUM, 2013).
Para criar nossa Lista Desordenada Ligada em Python, vamos começar criando duas
classes: a classe Node e a classe UnorderedList. A classe Node irá conter o campo de
dados e a referência do próximo nó, enquanto a classe UnorderedList será a
responsável pela coleção de nós.
A Imagem 2 traz o código a ser implementado para a classe Node,ao analisar o
código é possível notar que tem dois atributos o “data” e o “next”, onde o “data” irá
conter realmente o valor do elemento e o “next” faz referência ao próximo nó. As
funções “setData()” e “getData()” são responsáveis por manipular os dados do nó,
inserindo e lendo, respectivamente, o dado de cada nó.
class Node:
   def __init__(self,element):
       self.data = element
       self.next = None
   def getData(self):
       return self.data
   def getNext(self):
       return self.next
   def setData(self,newdata):
       self.data = newdata
   def setNext(self,newnext):
       self.next = newnext
53
Imagem 3 – Representação gráfica instância da classe Node.
Fonte: Próprio autor.
Imagem 4 – Classe UnorderedList em Python.
Ao analisar a Imagem 2, vemos o método __init__ que é o construtor, ou seja, é
executado cada vez que um novo nó for criado. Nesse método, é informando o
parâmetro “element” que é o dado em si que estará presente representado no nó.
Outro detalhe importante nesse método é o atributo next, que faz referência ao
próximo nó, e neste caso, é criada uma referência vazia ou None.
A Imagem 3 é uma representação gráfica de um nó criado pela nossa classe Node.
Podemos ver a instância de Node, representada pelo círculo, e está contida em uma
variável. O atributo next faz referência a algo nulo (None).
Com a nossa classe Node criada, precisamos criar a classe que irá definir a lista em si e
controlar os nós, tornando possíveis as operações e referências aos nós. Para isso,
iremos criar a classe UnorderedList, no momento criada no mesmo arquivo que a
classe Node. A Imagem 4 traz o código que implementa a classe em questão.
class UnorderedList:
   def __init__(self):
       self.head = None
   def isEmpty(self):
       return self.head == None
   def add(self,element):
54
       temp = Node(element)
       temp.setNext(self.head)
       self.head = temp
   def size(self):
       current = self.head
       count = 0
       while current != None:
           count = count + 1
           current = current.getNext()
       return count
   def search(self,element):
       current = self.head
       found = False
       while current != None and not found:
           if current.getData() == element:
               found = True
           else:
               current = current.getNext()
       return found
   def remove(self,element):
       current = self.head
       previous = None
       found = False
       while not found:
           if current.getData() == element:
               found = True
           else:
               previous = current
               current = current.getNext()
       if previous == None:
           self.head = current.getNext()
       else:
55
Fonte: autor.
Imagem 5 – Método isEmpty na classe UnorderedList.
Fonte: Próprio autor.
Imagem 6 – Método add na classe UnorderedList.
Fonte: Próprio autor.
           previous.setNext(current.getNext())
Ao analisar a Imagem 4, o primeiro ponto de atenção é no método construtor (__init__)
que já cria um atributo para definirmos o nó inicial da nossa lista. Esse ponto define
se a lista está vazia ou não. O método isEmpty() retorna se a lista está vazia ou não,
mostrado com detalhe na Imagem 5. Esse método compara o atributo head da lista,
se este estiver None, significada que a lista está vazia.
def isEmpty(self):
   return self.head == None
Para fazer a inserção de um novo nó na lista, existe o método add, que irá criar um
novo nó com o valor do elemento passado por parâmetro. Importante notar o local
da lista onde será inserido o novo nó, sem esquecer que estamos trabalhos com uma
estrutura de lista ligada, logo, sempre inserimos um novo nó pela ponta da lista.
Nesse caso, será necessário o atributo head da lista, colocando como referência o
novo nó criado. A Imagem 6 demonstra com detalhes o método add.
def add(self,element):
   temp = Node(element)
   temp.setNext(self.head)
   self.head = temp
56
Imagem 7 – Método remove na classe UnorderedList.
Fonte: autor.
Outro método importante e que merece atenção para analisar as ações necessárias é
o remove(). Para o seu funcionamento perfeito, é necessário fazer uma busca para
identificar qual elemento será removido. Novamente, por ser uma lista encadeada, a
cada alteração realizada na estrutura é necessário atualizar a referência entre os nós
para que não ocorram erros ou se percam dados. Assim, o nó antecessor ao
removido fará referência ao posterior.
A Imagem 7 traz o método remove por completo. Repare que existe uma estrutura de
repetição while para iterar entre os nós presentes na lista e caso o elemento desejado
seja encontrado, será feita a remoção do nó e a alteração das referências. Caso o nó
seja o primeiro da fila, então o nó head será alocado para fazer referência ao nó
posterior ao que está sendo removido.
def remove(self,element):
   current = self.head
   previous = None
   found = False
   while not found:
       if current.getData() == element:
           found = True
       else:
           previous = current
           current = current.getNext()
   if previous == None:
       self.head = current.getNext()
   else:
       previous.setNext(current.getNext())
57
06
Listas Lineares 
Ordenadas
O primeiro passo ao se pensar no desenvolvimento de uma lista ligada é entender
que cada elemento ou nó é relativo aos seus nós vizinho, antecessor e posterior. Caso
seja o primeiro nó, é apenas o posterior. Porém, imaginemos que precisamos inserir
um novo nó em nossa lista, mas o funcionamento normal das Listas e Dicionários em
Python é inserir o elemento no final da lista, sem se preocupar com a ordem naquele
momento (SZWARCFITER e MARKENZON, 2017; MILLER e RANUM, 2013; GUIMARÃES,
1984).
Vamos supor uma lista de idade que sempre deve apresentar do mais novo para o
mais velho. Imediatamente após ser modificada, entra o papel da lista ordenada,
onde a ordenação é tipicamente ascendente ou descendente – isso supondo que já
esteja definida qual é a operação de comparação que vai definir isso.
Podemos relacionar algumas operações para Lista Ordenadas que são próximas às
demais listas, como: 
59
Tabela 1 – Operações para Listas Desordenadas em Python
Fonte: Próprio autor.
Operador Descrição
OrderedList() Cria uma nova lista ordenada vazia.
add(elemento)
Insere um novo nó na lista, certificando-se de que a ordem
é preservada.
remove(elemento) Remove o nó da lista. Supõe que o elemento esteja na lista.
search(elemento)
Procura o elemento na lista. Retorna um booleano (bool);
True se o item está na lista ou False se falhar.
isEmpty()
Testa se a lista está vazia. Retorna um booleano (bool); True
se a lista está vazia e False caso a lista não esteja vazia.
size() Retorna o número de nós na lista. Retorna um inteiro.
index(elemento) Retorna a posição de um elemento na lista.
pop()
Remove e retorna o último elemento da lista, tendo que a
lista deve ter no mínimo um elemento.
pop(posição)
Remove e retorna o elemento em uma determinada
posição.
60
Imagem 2 – Exemplo de Lista Ligada Ordenada
Fonte: Próprio autor.
A implementação das listas ordenadas e não ordenadas compartilha diversas
operações, pois a base do funcionamento das listas lineares é a mesma. Para a
implementação de listas ordenadas, é importante lembrar ainda as posições relativas,
onde um nó faz referência a outro nó, criando um encadeamento dos elementos, que
é essencial para manutenção e sucesso da estrutura (SZWARCFITER e MARKENZON,
2017; MILLER e RANUM, 2013).
A Imagem 2 apresenta um exemplo de Lista Ligada Ordenada já com nós
representados.
Para a implementação de listas ordenadas, também vamos criar duas classes uma
Node para representar cada nó da nossa lista e outra classe para a lista em si, nesse
caso, a classe OrderedList.
A classe Node utilizada para lista ordenada é a mesma utilizada para lista
desordenada, pois a base das listas lineares ligadas, o nó, apresenta o mesmofuncionamento e sempre contém um valor e faz referência a outro nó. O que muda é
como a lista itera e representa os elementos.
A Imagem 3 apresenta a classe Node desenvolvida para ser aplicada com listas
ordenadas.
61
Imagem 3 – Classe Node em Python – Lista Ordenadas.
Fonte: autor.
class Node:
   def __init__(self,element):
       self.data = element
       self.next = None
   def getData(self):
       return self.data
   def getNext(self):
       return self.next
   def setData(self,newdata):
       self.data = newdata
   def setNext(self,newnext):
       self.next = newnext
Assim como a classe Node pode ser compartilhada entre estrutura de listas ordenadas
e não ordenadas, algumas operações da lista em si podem ser compartilhas também,
neste caso, os métodos isEmpty() e size(). Ambas as funções continuam se
comportando da mesma forma, pois não precisam se preocupar com como a lista
está organizada.
O método remove, mesmo que realize iterações dentro da lista para encontrar o nó a
ser removido, pode também ser aproveitado na classe de listas ordenadas, pois neste
caso a ordenação diferente não vai impossibilitar a busca. Por outro lado, pode até
ser mais rápida a execução. Dessa forma, apenas os métodos search() e add()
necessitam de alterações para ter o devido funcionamento.
62
Imagem 4 – Método search – Lista Ordenadas.
Fonte: autor.
A alteração no método search() é necessária, pois sabendo que a lista é ordenada,
podemos otimizar sua execução, e a cada nó testado validamos se o valor é menor
que o valor presente no caso. E caso seja, isso quer dizer que já foram testadas todas
as possibilidades de sucesso e o valor não foi encontrado, assim não precisamos
percorrer a lista inteira.
Por exemplo, se quisemos encontrar o valor 11 na lista da Imagem 2, quando o
algoritmo testar o nó que tem o valor 9, ele vai ver que o valor é diferente, porém, 11
ainda é maior que 9, então ele testa o próximo nó, com valor 13. O valor não é o que
queríamos, mas 11 é menor que 13, e como a lista é ordenada, quer dizer que existe
11 em mais nenhum nó da lista, já interrompendo a busca.
A Imagem 4 demonstra como ficou a implementação deste método com as alterações
citadas.
def search(self,element):
   current = self.head
   found = False
   stop = False
   while current != None and not found and not stop:
       if current.getData() == element:
           found = True
       else:
           if current.getData() > element:
               stop = True
           else:
               current = current.getNext()
 
   return found
63
Imagem 5 – Método add – Lista Ordenadas.
Todavia, o método que sofre a maior alteração para a implementação de listas
ordenadas ligadas é o método de inclusão de novos nós e elementos, pois o ele já
deve inserir o novo valor em uma posição que já esteja ordenada. Para isso, é
necessário criar uma iteração dentro da lista para buscar o local onde o nó se encaixa,
ou seja, onde o seu antecessor é menor que o novo elemento e o posterior seja maior
que o novo elemento também.
Para isso, é utilizada uma estrutura similar ao método search que iremos iterar dentro
da lista até encontrar a melhor posição. Caso não a encontre, o novo é inserido no
final da lista, pois indicada ser o elemento com maior valor. Porém, caso seja
encontrado um intervalo que o mesmo será inserido, deve-se identificar onde foi o nó
da busca e fazer as alterações necessárias. A Imagem 5 demonstra como ficou o
método add com as alterações.
Com essas alterações feitas na classe, temos pronta a implementação da estrutura de
Lista Ligada Ordenada, utilizando das classes Node e OrderedList. A Imagem 6
demonstra como ficou a implementação da classe OrderedList.
def add(self,element):
       current = self.head
       previous = None
       stop = False
       while current != None and not stop:
           if current.getData() > element:
               stop = True
           else:
               previous = current
               current = current.getNext()
       temp = Node(element)
       if previous == None:
           temp.setNext(self.head)
           self.head = temp
64
Fonte: autor.
Imagem 6 – Classe OrderedList.
       else:
           temp.setNext(current)
           previous.setNext(temp)
class OrderedList:
   def __init__(self):
       self.head = None
   def search(self,element):
       current = self.head
       found = False
       stop = False
       while current != None and not found and not stop:
           if current.getData() == element:
               found = True
           else:
               if current.getData() > element:
                   stop = True
               else:
                   current = current.getNext()
       return found
   def add(self,element):
       current = self.head
       previous = None
       stop = False
       while current != None and not stop:
           if current.getData() > element:
65
Fonte: autor.
               stop = True
           else:
               previous = current
               current = current.getNext()
       temp = Node(element)
       if previous == None:
           temp.setNext(self.head)
           self.head = temp
       else:
           temp.setNext(current)
           previous.setNext(temp)
 
   def isEmpty(self):
       return self.head == None
 
   def size(self):
       current = self.head
       count = 0
       while current != None:
           count = count + 1
           current = current.getNext()
       return count
66
07
Pilhas
Uma pilha, ou no inglês stack, assim como as demais listas lineares vistas até o
momento, é uma coleção de itens, neste caso de maneira ordenada. Sua principal
diferença com as demais é que a inserção de novos itens e a remoção de itens já
existentes ocorrem sempre na mesma extremidade ou fila, onde tal ponto é
normalmente chamado de topo, enquanto a outra extremidade é conhecida como
base (SZWARCFITER e MARKENZON, 2017; MILLER e RANUM, 2013; GUIMARÃES,
1984).
Ao analisar uma pilha, sempre que se notarem os elementos mais próximos da
extremidade base, quer dizer que são itens que estão na pilha há mais tempo. Assim,
o elemento que estiver mais próximo do topo ou no topo, quer dizer que foi inserido
na pilha mais recentemente ou foi o último inserido, logo, deixará a pilha antes.
Sempre o último inserido será o primeiro a ser removido, e esse conceito é tido como
LIFO (last-in firt-out) (SZWARCFITER e MARKENZON, 2017; MILLER e RANUM, 2013;
GUIMARÃES, 1984).
Podemos observar diversas pilhas implementadas no mundo real, ao nosso
redor, quando vamos a um restaurante self-service, por exemplo. Precisamos
pegar a bandeja para nos servir, e há uma pilha de bandejas, em que os
clientes sempre vão retirar a que está mais em cima e as bandejas novas
que chegarem serão utilizadas primeiro. Podemos também pensar em uma
pilha de pratos, livros, roupas na gaveta do armário e outros cenários, mas é
um conceito importante de sempre ter em mente, pois ele aparece em
diversas aplicações computacionais.
Observando bem o comportamento das pilhas, podemos notar um que é   muito
importante para as aplicações computacionais, em que a ordem que os elementos
são removidos da pilha é o inverso da ordem de inserção, e assim são aplicadas para
68
Imagem 2 – Comportamento de uma pilha de dados.
Fonte: Adaptado de Miller e Ranum, 2013.
a inversão ou reversão de processos. A Imagem 2 demonstra como seria a ordem de
chegada e saída de uma pilha (SZWARCFITER e MARKENZON, 2017; MILLER e RANUM,
2013).
Você consegue pensar em alguma aplicação das pilhas no seu dia a dia com
o uso do celular com computador? Uma aplicação que usamos quase
diariamente é o botão voltar do navegador ou de qualquer outro app, em
que se vai criando uma pilha das páginas que navegamos, e toda vez que o
“voltar página” é chamado, ele tira o último elemento da pilha – neste caso, a
página – e apresenta no navegador novamente. Quanto maisantiga a
página, mais na base da pilha está e mais vai demorar a sair.
69
Para implementar uma pilha em Python, podemos relacionar algumas operações que
devem ser contempladas, assim, a Tabela 1 apresenta as possíveis operações sobre
uma pilha.
Tabela 1 – Operações para Pilhas em Python
Fonte: Próprio autor.
Operador Descrição
Stack() Cria uma nova pilha vazia.
push(elemento) Insere um novo elemento na pilha.
pop() Remove o elemento no topo da pilha e retorna o elemento.
peek()
Retorna o elemento no topo da pilha, mas não remove da
pilha.
isEmpty()
Testa se a pilha está vazia. Retorna um booleano (bool); True
se a pilha está vazia e False caso não esteja vazia.
size() Retorna o número de elementos na pilha. Retorna um inteiro.
Vamos dar início à implementação da nossa própria pilha em Python. Como já vimos,
o Python conta com diversos recursos que podem facilitar o desenvolvimento de
novas estruturas de dados e tipos de dados abstratos. Assim, para desenvolver a
nossa pilha, vamos criar uma nova classe com nome de Stack e utilizar uma lista
nativa de Python como base. Tendo isso, vamos escrever as operações que vimos na
Tabela 1 como métodos da nossa nova classe.
Ainda contamos com alguns métodos nativos para listas que podem nos auxiliar na
nossa pilha, como o append() e o pop(). Só temos que ficar atentos qual das
extremidades da lista vamos utilizar como topo e qual será a base. Na nossa
implementação, vamos assumir que o final da lista terá o elemento do topo, ou seja,
aquele mais recente na pilha, assim podemos usar o append() junto à operação de
push e o pop().
70
Imagem 3 – Classe Stack para implementação de pilhas em Python.
Fonte: autor.
A Imagem 3 traz o código da classe Stack, ou seja, nossa implementação de pilha.
Nota-se que no método construtor existe a declaração de uma variável elements que é
uma lista Python vazia, e os demais métodos como push e pop utilizam os métodos
Python a partir desta variável elements.
class Stack:
    def __init__(self):
        self.elements = []
 
    def isEmpty(self):
        return self.elements == []
 
    def push(self, item):
        self.elements.append(item)
 
    def pop(self):
        return self.elements.pop()
 
    def peek(self):
        return self.elements[len(self.elements)-1]
 
    def size(self):
        return len(self.elements)
A Imagem 4 traz uma execução da pilha criada por nós, utilizando como exemplo o
cenário de entrada e saída que utilizamos na Figura 2 para demonstrar o
funcionamento de uma pilha.
71
Imagem 4 – Exemplo de execução de uma pilha.
Fonte: autor.
>>> pilha = Stack ()
>>> print (pilha.isEmpty())
True
>>> pilha.push(10)
>>> pilha.push(20)
>>> pilha.push(pilha.peek())
20
>>> pilha.push(True)
>>> print(pilha.size())
3
>>> print(pilha.isEmpty())
False
>>> pilha.push("AB")
>>> print(pilha.pop())
AB
>>> print (pilha.pop())
True
>>> print (pilha.size())
2
72
08
Filas
A fila, ou queue em inglês, é uma coleção de itens de maneira ordenada, cujo
funcionamento normal se aproxima da estrutura de pilha. Porém, sua principal
diferença em relação à pilha é que a inserção de novos elementos na estrutura
acontece em uma extremidade, normalmente no “fim” (rear), enquanto a remoção
dos elementos ocorre do outro lado da fila, o “início” (front) (SZWARCFITER e
MARKENZON, 2017; MILLER e RANUM, 2013; GUIMARÃES, 1984).
Diferentemente da pilha em que o último elemento inserido na estrutura é o primeiro
a sair, nas filas o elemento inserido no fim da fila faz todo o caminho, respeitando a
ordem de chegada até que seja o próximo elemento a ser removido.
Assim, o elemento que estiver há mais tempo na fila está mais próximo de sair, logo, o
primeiro a entrar é o primeiro a sair, conceito tido como FIFO (first-in firt-out). A
estrutura de uma fila é bem definida e restritiva, pois tem apenas uma forma de
entrada e uma forma de saída, e não é permitido furar a fila ou sair antes de ter
esperado o tempo ou ordem correta (SZWARCFITER e MARKENZON, 2017; MILLER e
RANUM, 2013; GUIMARÃES, 1984). 
Assim como podemos encontrar pilhas ao nosso redor no mundo, a fila está
tão presente quanto. Os exemplos são inúmeros: filas de cinema e
restaurante, lista de chamada da faculdade e até mesmo calendários ou
listas de afazeres. Pensando dentro da Tecnologia da Informação, temos
diversos cenários possíveis, como o escalonamento de tarefas de um
processador (scheduling) ou uma impressora, que gerencia a fila de
impressões por ordem de chegada.
A Imagem 2 traz um representação gráfica de como a fila gerencia seus elementos e
como seguem o fluxo do fim até o início.
74
Imagem 2 – Comportamento de uma fila de dados.
Fonte: Adaptado de Miller e Ranum, 2013.
A estrutura de dados é também um tipo de dado abstrato que conta com estrutura e
operações bem definidas e que permitem organizar o fluxo de elementos inseridos e
removidos. É importante lembrar sempre do fluxo dentro da fila para definir as
operações. Os novos elementos são inseridos no fim da fila (assim como no mundo
real) e são removidos no início da fila (MILLER e RANUM, 2013).
Tendo isso claro, a Tabela 1 relaciona e define as operações necessárias para a
construção de uma estrutura de dados de fila.
Tabela 1 – Operações para filas em Python
Fonte: Próprio autor.
Operador Descrição
Queue() Cria uma nova fila vazia.
enqueue(elemento) Insere um novo elemento no final da fila.
dequeue()
Remove o elemento do início da fila. Retorna um elemento
e altera a fila.
isEmpty()
Testa se a fila está vazia. Retorna um booleano (bool); True
se a fila está vazia e False caso não esteja vazia.
size()
Retorna o número de elementos na fila. Retorna um
inteiro.
75
Vamos dar início à implementação da nossa própria fila em Python. Como já vimos, o
Python conta com diversos recursos que podem facilitar o desenvolvimento de novas
estruturas de dados e tipos de dados abstratos. Para desenvolver a nossa fila, vamos
criar uma nova classe com nome de Queue e novamente utilizar uma lista nativa de
Python como base, assim como fizemos com a pilha. Tendo isso, vamos escrever as
operações que vimos na Tabela 1 como métodos da nossa nova classe.
Ainda contamos com alguns métodos nativos para listas que podem nos auxiliar na
nossa fila, tais como o insert() e o pop(). Só temos que ficar atentos qual das
extremidades da lista utilizar como fim e qual será o início. Na nossa implementação,
vamos assumir que o fim da fila está na posição 0 da lista, e desta maneira, podemos
usar a função insert(), nativa do Python, para adicionar elementos novos no final da
fila.
Também iremos aplicar a função pop() para remover os elementos no início da fila, e
atente-se bem: o fim da nossa fila será na posição 0 da lista (início da lista) e o nosso
início da fila, onde os elementos serão retirados, é o fim da lista (último elemento da
lista).
A Imagem 3 traz o código da classe Queue, ou seja, na nossa implementação de fila,
nota-se que no método construtor existe a declaração de uma variável elements, que é
uma lista Python vazia, e os demais métodos como insert e pop utilizam os métodos
Python a partir desta variável elements.
76
Imagem 3 – Classe Queue para implementação de filas em Python.
Fonte: autor.
class Queue:
   def __init__(self):
       self.elements = []
   def isEmpty(self):
       return self.elements == []
   def enqueue(self, item):
       self.elements.insert(0,item)
   def dequeue(self):
       return self.elements.pop()
   def size(self):
       return len(self.elements)
A Imagem 4 traz uma execução da fila criada por nós, utilizando como exemplo o
cenário de entrada e saída que utilizamos na Figura 2 para demonstrar o
funcionamento de uma fila.
77
Imagem 4 – Exemplo de execução de uma fila.
Fonte: autor.
>>> from Queue import Queue
>>> fila = Queue()
>>> fila.enqueue(10)
>>> fila.enqueue(20)
>>> print(fila.size())
2
>>> fila.enqueue(True)
>>> print(fila.size())
3
>>> print(fila.isEmpty())
False
>>> fila.enqueue("AB")>>> fila.dequeue()
10
>>> fila.dequeue()
20
>>> print(fila.size())
2
78
09
Deque
Imagem 2 – Comportamento de um deque de dados.
Fonte: Adaptado de Miller e Ranum, 2013.
A estrutura de dados deque, ou também fila de duas extremidades, assim como as
estrutura de dados que vimos, é uma coleção de dados ordenada de elementos. A
estrutura de construção de um deque se aproxima da fila, porém com algumas
diferenças que fazem diferença nas suas funcionalidades.
Assim como a pilha e a fila, um deque possui duas extremidades, em que uma é o
início (front) e outra é o fim (rear). Os elementos continuam com posições referentes
dentro da estrutura. Porém, diferentemente das filas, o deque tem uma natureza
menos restritiva de inclusão e exclusão de elementos, assim, novos elementos podem
ser incluídos e excluídos no início ou no fim da estrutura (SZWARCFITER e
MARKENZON, 2017; MILLER e RANUM, 2013).
O deque se caracteriza como uma estrutura híbrida, ou seja, pode assumir as
capacidades de pilhas e filas, dependendo de como for executada – isso em uma
única estrutura. É importante ressaltar, todavia, que mesmo que o deque possa
assumir o comportamento de pilhas e filas, um deque não é necessário à ordenação
LIFO ou FIFO como a fila e a pilha. A principal responsabilidade da estrutura é
promover o uso consistente das operações de inclusão e exclusão de elementos
(MILLER e RANUM, 2013).
A Imagem 2 traz uma representação gráfica de como o deque gerencia seus
elementos e como é possível fazer as ações de inclusão e exclusão do fim ou no início
da estrutura. 
A estrutura de dados é também um tipo de dado abstrato, contando com estrutura e
operações bem definidas que permitem organizar o fluxo de elementos inseridos e
removidos. É importante lembrar sempre do fluxo dentro da fila para definir as
operações, e os novos elementos podem ser alterados nas duas pontas, ou seja,
pode-se incluir ou excluir tanto no fim da fila quanto no início dela.  Por esse motivo, o
deque é conhecido como fila dupla (MILLER e RANUM, 2013).
80
Tendo isso claro, a Tabela 1 relaciona e define as operações necessárias para a
construção de uma estrutura de dados de deque.
Tabela 1 – Operações para Deque em Python
Fonte: Próprio autor.
Operador Descrição
Deque() Cria um novo deque vazio.
addFront(elemento) Insere um novo elemento no início do deque.
addRear(elemento) Insere um novo elemento no fim do deque.
removeFront()
Remove o elemento do início do deque. Retorna um
elemento e altera o deque.
removeRear()
Remove o elemento do fim do deque. Retorna um
elemento e altera o deque.
isEmpty()
Testa se o deque está vazio. Retorna um booleano (bool);
True se o deque está vazio e False caso não esteja vazio.
size()
Retorna o número de elementos no deque. Retorna um
inteiro.
Vamos dar início à implementação do nosso deque em Python. Como já vimos, o
Python conta com diversos recursos que podem facilitar o desenvolvimento de novas
estruturas, e para desenvolver o nosso deque, vamos criar uma nova classe com
nome de Deque e novamente utilizar uma lista nativa de Python como base. Tendo
isso, vamos escrever as operações que vimos na Tabela 1 como métodos da nossa
nova classe.
Ainda contamos com alguns métodos nativos para listas que podem nos auxiliar no
nosso deque, como o insert(), append() e pop(). Só temos que ficar atentos a qual das
extremidades da lista vamos utilizar como fim e qual será o início. Na nossa
81
Imagem 3 – Classe Deque para implementação de filas duplas em Python.
Fonte: autor.
implementação, vamos assumir que o fim da fila está na posição 0 da lista
A Imagem 3 traz o código da classe Deque, ou seja, na nossa implementação de
deque, nota-se que no método construtor existe a declaração de uma variável
elements que é uma lista Python vazia, e os demais métodos como add e remove
utilizam os métodos Python a partir desta variável elements.
class Deque:
   def __init__(self):
       self.elements = []
   def isEmpty(self):
       return self.elements == []
   def addFront(self, item):
       self.elements.append(item)
   def addRear(self, item):
       self.elements.insert(0,item)
   def removeFront(self):
       return self.elements.pop()
   def removeRear(self):
       return self.elements.pop(0)
   def size(self):
       return len(self.elements)
82
Imagem 4 – Exemplo de execução de uma fila.
Fonte: autor.
A Imagem 4 traz uma execução do deque criado por nós, utilizando como exemplo o
cenário de entrada e saída que utilizamos na Figura 2 para demonstrar o
funcionamento de um deque.
>>> from Deque import Deque
>>> deque = Deque()
>>> print(deque.isEmpty())
True
>>> deque.addRear(10)
>>> deque.addRear(20)
>>> deque.addFront("AB")
>>> deque.addFront(True)
>>> print(deque.size())
4
>>> print(deque.isEmpty())
False
>>> deque.addRear(5.5)
>>> print(deque.removeRear())
5.5
>>> print(deque.removeFront())
True
83
10
Matrizes
Vimos até agora diversas estruturas de dados e como lidar com coleções de dados,
passando por tipos nativos do Python tais como listas e dicionários, mas também por
tipos de dados abstratos como listas ligadas, filas e pilhas. Porém, até agora todas as
estruturas têm algo em comum sobre o espaço dos dados: estão distribuídos em uma
única dimensão, o que pode limitar em alguns pontos a organização e distribuição
dos dados.
Agora, veremos o conceito de matrizes, que se caracterizam por serem estruturas de
dados bidimensionais, assemelhando-se a uma tabela e possuindo M linhas para N
colunas. O conceito de matriz tem sua origem na matemática, e são aplicadas em
diversas soluções importantes, por exemplo, para fazer análise de dispersão ou
resolução de sistemas de equações lineares (SZWARCFITER e MARKENZON, 2017;
PERKOVIC, 2016; GUIMARÃES, 1984).
Podemos olhar então uma matriz como uma lista multidimensional, ou seja, um vetor
com vetores.
Mas como podemos pensar nisso com a linguagem Python? Em Python, pensar como
uma lista de lista, ou seja, cada elemento de uma lista, como vimos anteriormente,
será uma lista (SZWARCFITER e MARKENZON, 2017; PERKOVIC, 2016). 
85
Imagem 2 – Exemplo matriz de alunos e notas.
Fonte: Próprio autor.
Para consolidar bem o conceito de matrizes, vamos pensar que precisamos
controlar as notas de uma turma de 10 alunos, porém, o aluno tem três
notas e precisamos implementar uma estrutura de dados que seja capaz de
associar 10 alunos com 3 notas, de forma que haja um controle e uma
relação entre cada aluno e suas respectivas notas.
Assim, podemos pensar da seguinte forma: criar uma lista em Python com
10 posições, onde cada posição se refere a um aluno, mas tem outra lista
com 3 posições para cada uma das notas. A Imagem 2 traz uma
representação gráfica de como ficaria a matriz para esse cenário.
Lembrado que assim como as listas, a contagem das posições sempre
começa em 0.
Como uma matriz é composta por um tipo nativo do Python de coleções (as listas), a
estrutura de dados é também um tipo de dado nativo, fazendo assim uso de todas as
funções e operações relacionadas a listas, como, por exemplo, a iteração e a
concatenação. Para a construção e a implementação de uma matriz, é necessário
86
Imagem 3 – Método para criação de matrizes com Python.
utilizar diversos recursos das estruturas de repetição tais como while e for. Com o uso
de ambas as estruturas junto com métodos personalizados é possível trabalhar com
matrizes em Python (SZWARCFITER e MARKENZON, 2017; PERKOVIC, 2016).
Para criar nossa primeira estrutura de dados com matrizes com Python, vamos
pensar em uma função capaz de receber o número de linhas e colunas necessárias,
então essa função ficará responsável por criá-las e depois veremos algumas formas
de iterar e navegar entre os dados de uma matriz.
A Imagem 3 demonstra o código da função feita para criar matrizes. A função recebe
três parâmetros, n_linhas, n_colunas e valor, que representam respectivamente a
quantidade de linhas que terá em nossa matriz, a quantidade de colunas que terá

Outros materiais