Você está na página 1de 16

1 APRESENTAÇÃO

1 APRESENTAÇÃO
Olá e seja muito bem-vindo ao nosso ebook “Estrutura de dados – Manipulando estruturas de
forma eficiente”, neste material nós vamos apresentar os principais conceitos introdutórios
desta importante área da programação. Vamos ensinar todos os fundamentos de estrutura de
dados, espero que com o conteúdo que nós vamos tratar, você possa alcançar o conhecimento
necessário desta área. Para iniciarmos o nosso curso, nós precisamos apresentar o conteúdo
programático deste material, inicialmente nós iremos apresentar os conceitos iniciais de estru-
tura de dados, abordando as diferenças dos tipos de dados. Após iremos falar sobre vetores e
matrizes, que são a base de uma estrutura de dados dinâmica, logo em seguida iremos começar
a falar de listas, após falarmos de lista iremos falar sobre pilha e no fim abordaremos sobre filas.
Por último queria me apresentar!
Sou Edinelson Junior, Professor EBTT titular do IFPA (Instituto Federal do Pará) campus
Itaituba, formado em Ciência da Computação e especialista em Banco de dados, tenho exper-
iência em desenvolvimento de aplicações Web. Caso queira acompanhar meus trabalhos, você
pode me procurar em meu blog https://cod3cafe.tech.

FIGURE 1: EDINELSON JUNIOR


Professor de Programação

Ebook Edinelson 2
CONTENTS

Contents

1 Apresentação 2

2 Conceitos Iniciais 4
2.1 Testando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

3 Vetores 6

4 Matrizes 9

5 Listas 11
5.1 Listas Circulares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
5.2 Lista duplamente encadeada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.3 Listas em Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

Ebook Edinelson 3
2 CONCEITOS INICIAIS

2 CONCEITOS INICIAIS

2.1 TESTANDO
Se você chegou até aqui, e quer aprender estrutura de dados, então você já teve algum tipo
de contato com as técnicas básicas de criação de algoritmos. Com os conhecimentos básicos
de criação de variáveis, estruturas condicionais, e funções, é possível criar programas que re-
solvam grande parte dos problemas do mundo, no entanto quando olhamos para problemas
mais complexos, nós percebemos que pra trabalhar com dados de forma eficiente, é necessário
trabalhar de forma organizada na memória, realizando ações mais sofisticadas do que simples
variáveis básicas. A organização de dados na memória permite a criação de algoritmos sofisti-
cados e eficientes. Para isso nós capítulos posteriores nós iremos estudar alguns tipos de es-
truturas fundamentais. São elas:

• Vetores;

• Matrizes;

• Matrizes;

• Matrizes;

• Matrizes;

• Matrizes;

• Matrizes;

• Registros

Mas antes de iniciarmos nossos estudos sobre essas estruturas, precisamos primeiramente
entender o conceito de “Estrutura de dados”:
“É uma coleção de dados que são definidos por meio de sua organização e operações que
podem ser realizadas com elas.”
O processo de criação de um software consiste na junção de um Algoritmo + Estrutura de
dados. Então o fluxo de resolução de um problema computacional, consiste basicamente , se-
gundo Figura 2:
Os dados que formam essas coleções podem ser desde:

• Dados simples:
Inteiro;
Real;
Caracter;
Lógico

Ebook Edinelson 4
2 CONCEITOS INICIAIS

FIGURE 2: FLUXO DE RESOLUÇÃO DE PROBLEMAS

• Dados estruturados:
Estáticos
Arrays;
Registros;
Arquivos;
Conjuntos;
Cadeias de caracteres(strings)
Dinâmico
Listas;
Pilhas;
Filas;
Árvores;
Grafos

Os tipos de dados simples significam que não são compostos de outras estruturas de dados.
Os dados estruturados estáticos são aquelas em que o seu tamanho precisa ser definido no
momento de sua criação. As estruturas dinâmicas não possuem limitações ou restrições no
tamanho de memória ocupada, além disso essas usam o conceito de ponteiro, que possibilita
construir estruturas de dados que são suportadas pelas principais linguagens de programação.

Ebook Edinelson 5
3 VETORES

3 VETORES
Antes de iniciarmos nossa explicação sobre arrays, nós vamos considerar um problema: “Ler
uma quantidade de valores inteiros além de imprimir os mesmos na ordem inversa que foi lida”,
os valores inteiros são: 4, 8, 10, 7, 1, logo nós queremos imprimir a saída da seguinte maneira:
1, 7, 10, 8, 4.
Para solucionar esse problema, com os conhecimentos básicos que temos de programação,
nós precisaríamos criar uma variável para cada número, que eu fosse ler, eu perderia da memória
do número anterior, a exigência do uso de tantas variáveis quanto o número de entradas, a cri-
ação da quantidade de variáveis necessitaria ser conhecida em “tempo de compilação”.
Para solucionar esse problema de forma eficiente nós podemos usar vetores, que são estru-
tura de dados que permitem o acesso a grande quantidade de dados em memória com apenas
uma variável. Isso quer dizer que ao criarmos um vetor, nós temos um espaço de memória que
tem acesso a muitas posições de memória, de maneira controlada.
Logo se criarmos um vetor com 5 espaços de memória nós trataríamos da seguinte maneira.

FIGURE 3: ESTRUTURA DE UM VETOR

Um vetor é uma estrutura de dados linear que necessita de somente um índice para seus el-
ementos serem indexados. Tem como característica de ser uma estrutura de dados homogênea,
pois armazena somente uma lista de valores do mesmo tipo, conforme a Figura 3, em que seus
elementos são do tipo inteiro.
Os vetores diferentemente das estruturas de dados dinâmicas, já vem embutido dentro das
principais linguagens de programação.
A definição de um array em Python funciona da mesma forma que uma variável qualquer,
em que definimos o nome do vetor e atribuímos uma coleção de dados que estão inseridos den-
tro de um parentese.

carros = ["Ford", "Volvo", "BMW"]

No código acima nós temos três elementos vinculados a coleção de carros, caso eu queira

Ebook Edinelson 6
3 VETORES

acessar um valor especifico, por exemplo do segundo carro, eu preciso especificar qual índice
eu devo acessar.

print(carros[1])

O resultado será:

"Volvo"

Além de acessar informações de um vetor, nós podemos alterar informações que estão in-
seridas em um elemento do nosso array.

carros[1] = "Ferrari"

Assim como qualquer outra variável, os vetores em Python possuem funções que podem
realizar ações com os dados contidos em seus índices, o primeiro que iremos tratar é o método
que retorna o tamanho do elemento do array.

print(len(carros))

Quando nós estamos manipulando um vetor, na maioria das vezes não sabemos qual o tamanho
de elementos que existe em sua estrutura, com o comando acima nós podemos saber o tamanho.
Além disso nós podemos acessa de forma dinâmica todos os elementos que estão inseridos no
vetor. Para isso nós usamos uma estrutura de repetição, que irá percorrer de forma dinâmica
todos os elementos.

for x in carros
print(x)

O resultado será:

Ford
Volvo
BMW

Outra operação que podemos fazer com um array já criado é adicionando novos elementos
no array, esta ação só é possivel graças ao método append.

carros.append("Toyota")

Após adicionarmos nós podemos pedir para imprimir os elementos do vetor com o a estru-
tura de repetição.

for x in carros
print(x)

Ebook Edinelson 7
3 VETORES

E o resultado será:

Ford
Volvo
BMW
Toyota

Outra importante ação que podemos fazer é remover um elemento de um vetor, para re-
alizar essa ação, nós podemos fazer usando o método pop.

carros.pop("Ford")

Ebook Edinelson 8
4 MATRIZES

4 MATRIZES
Matrizes nada mais é do que um vetor bidimensional, em que nós definimos mais de uma dimen-
são de elementos em sua estrutura, geralmente, essa definição separa os índices em colunas e
linhas, com sua estrutura semelhante a uma tabela, conforme Figura 4.

FIGURE 4: ESTRUTURA DE UMA MATRIZ

Na figura acima nós percebemos que uma matriz é um array com duas dimensões, uma pra
definir a quantidade de linhas e a outra pra definir a quantidade de colunas (índices).
Em relação a um vetor, uma matriz se difere pois ela é um arranjo bidimensional ou multi-
dimensional de alocação estática de elementos e trabalha de forma sequencial. Ela necessita
também de um incide para referenciar a linha e outro pra referenciar a sua coluna.
Da mesma forma que um vetor, uma matriz também pode ter tamanhos variados, todos os
elementos são do mesmo tipo, cada elemento contém somente um valor e os tamanhos dos val-
ores são os mesmos. Os elementos ocupam posições sequenciais na memória. A alocação pode
ser feita colocando elementos linha-por-linha ou coluna-por-coluna. A definição de Matrizes
em Python funciona da seguinte maneira:

notas_alunos = [[9.5, 10 , 9.8, 9.9], [10, 9.5, 8.9, 9.1]]

No exemplo acima, nós criamos uma matriz com o nome notas_alunos que tem o tamanho
[2, 2], pois tem duas linha e duas coluna.
Caso queira acessar individualmente um índice eu posso realizar da seguinte maneira:

Ebook Edinelson 9
4 MATRIZES

notas_alunos[0][2]

O resultado será:

9.8

Outras operações que podemos realizar são as mesmas que usamos com um vetor, no en-
tanto devemos entender que para realizar este tipo de ação, nós estamos modificando os el-
ementos de apenas uma linha, logo você deve tomar cuidado ao realizar operações com ma-
trizes.

Ebook Edinelson 10
5 LISTAS

5 LISTAS
As Listas são uma estrutura de dados dinâmica formada por uma sequência de elementos chama-
dos de nós, que contém dois campos: dado e endereço. O primeiro armazena o real elemento
da lista e o segundo armazena o próximo nó da lista.
O endereço, que é usado para acessar um nó especifico, é conhecido como ponteiro. A lista
é acessada a partir de um ponteiro externo que aponta para o primeiro elemento da lista, além
de conter o endereço do primeiro nó.
Quando falamos de um ponteiro externo, nós estamos falando de um elemento que não
está incluído dentro do nó. O seu valor é acessado diretamente, por referência a uma variável.
O campo do próximo endereço do último nó da lista contém um valor especial, conhecido
como NULL, que não é um endereço válido. Este ponteiro nulo é usado para indicar o fim da
minha lista. Uma lista é chamada de Vazia ou lista nula caso não tenha nós ou tenha apenas um
nó sentinela, a estrutura de um nós pode ser definida conforme Figura 5.

FIGURE 5: DEFINIÇÃO DE UM NÓ EM UMA LISTA

Percebam que pra armazenar o valor Ana, eu tenho dentro de um nó dois elementos. O
primeiro é o elemento que armazena o dado e o segundo é um ponteiro que aponta para o próx-
imo elemento, conforme a figura, nós sabemos que o próximo elemento deve conter o dado
Maria, logo o valor 2 que está referenciando o ponteiro, deve apontar para o próximo nó.
O fluxo de elementos da lista pode ser melhor entendido na Figura 8.
Percebam que todos os três primeiros elementos da lista possuem valor e um ponteiro apon-
tando para o próximo nó, mas percebam que ao chegarmos no último nó, não temos nem o
dado e também não temos o valor do ponteiro, conforme foi descrito nos parágrafos anteri-
ores, quando chegamos em um ponteiro nulo, nós chegamos no final de uma lista.

Ebook Edinelson 11
5 LISTAS

FIGURE 6: DEFINIÇÃO DE UMA LISTA ENCADEADA

5.1 LISTAS CIRCULARES


Na parte inicial deste capitulo nós vimos a definição de uma lista encadeada. Caso eu queira
fazer uma adaptação desta estrutura eu posso realizar uma mudança, de modo que o campo do
ponteiro no último nó contenha um ponteiro de volta para o primeiro nó, em vez de um ponteiro
nulo. Este tipo de lista é conhecido como circular, pois a partir de qualquer ponto, é possível
atingir qualquer outro ponto da lista.

FIGURE 7: DEFINIÇÃO DE UMA LISTA CIRCULAR

Observe que agora não temos um índice inicial e final naturalmente. Precisamos, definir um

Ebook Edinelson 12
5 LISTAS

primeiro nós e um último nó por convenção. Uma convenção é permitir que o ponteiro externo
para a lista circular aponte para o último elemento, em que o seguinte se torne o primeiro nó,
logo podemos incluir e remover novos elementos a partir do inicio ou do final da lista.
Esse tipo de lista possui uma limitação em relação a lista duplamente encadeada (próxima
sessão), pois a mesma só pode ir para o próximo item, logo caso eu queira voltar para um item
anterior, eu teria que percorrer toda lista para chegar no item anterior.

5.2 LISTA DUPLAMENTE ENCADEADA


Embora uma lista circular tenha vantagens em relação a uma lista encadeada simples, ela ainda
apresenta algumas limitações. Conforme mencionei anteriormente eu só posso acessar os ele-
mentos no sentido normal, caso eu queira acessar um nó anterior eu não posso atravessar uma
lista no sentido contrário. No caso em que eu necessite voltar em um nó anterior, a estrutura
de dados adequada nesse caso é uma lista duplamente encadeada.

FIGURE 8: DEFINIÇÃO DE UMA LISTA DUPLAMENTE ENCADEADA

Cada nós da lista contém dois ponteiros, um para seu predecessor e outro pro seu suces-
sor. Podemos então considerar os nós de uma lista duplamente encadeada contendo três ele-
mentos, um campo de dados, que contem as informações armazenadas, os nós lef e right, que
contém os ponteiros para os nós em ambos os lados. Estando em um elemento (nó), eu posso
acesso os elementos adjacentes e, dado um ponteiro para o último elemento, pode-se recorrer
a lista de ordem inversa.
Existem cinco operações básicas sobre uma lista encadeada:

• Criação

Ebook Edinelson 13
5 LISTAS

• Busca

• Inclusão

• Remoção

• Destruição

5.3 LISTAS EM PYTHON


As listas são estruturas de dados em Python que são a base para outras estruturas mais com-
plexas.
As ações que podemos fazer com listas em Python são:

• append

• extend

• insert

• remove

• pop

• clear

• count

• sort

• reverse

• copy

Para exemplificar, nós podemos usar estes métodos para fins de demonstração.

>>> frutas = ['laranja', 'maçã', 'pera', 'banana', 'caju', 'maçã', 'banana']


>>> frutas.count('maçã')
2
>>> frutas.count('tangerine')
0
>>> frutas.index('banana')
3
>>> frutas.index('banana', 4)
>>> frutas.reverse()
>>> frutas

Ebook Edinelson 14
5 LISTAS

['banana', 'maçã', 'caju', 'banana', 'pera', 'maçã', 'laranja']


>>> frutas.append('uva')
>>> frutas
['banana', 'maçã', 'caju', 'banana', 'pera', 'maçã', 'laranja', 'uva']
>>> frutas.sort()
>>> frutas
['banana', 'banana', 'caju', 'laranja','maçã', 'maçã', 'pera', 'uva']
>>> frutas.pop()
'uva'

Uma outra forma de implementar em python seria da seguinte maneira:

class no_lista:
"""
classe que define um nó, que possui o dado e o
ponteiro para o próximo nó
"""

def __init__(self, dado=0, proximo_no=None):


self.dado = dado
self.proximo = proximo_no
def __repr__(self):
return '%s -> %s' % (self.dado, self.proximo)

class lista_encadeada:
"""
classe que define a criação de uma lista, que deve
ter a cabeça, que é o último elemento inserido,
caso náo tenha, ele retornara none
"""

def __init__(self):
self.cabeca = None
def __repr__(self):
return "[" + str(self.cabeca) + "]"

Ebook Edinelson 15
5 LISTAS

def insercao_novo_elemento(lista, novo_dado):


"""
estou passando a lista como parametro e tambem o novo elemento
função que inser novo elemento na lista encadeada
"""

novo_no = no_lista(novo_dado)
#novo_no recebe no_lista(com o novo elemento)

novo_no.proximo = lista.cabeca
"""
proximo nó recebe a lista cabeça,
caso seja none ele irá inserir none,
senão pegará o novo valor
"""

lista.cabeca = novo_no #cabeça atualiza com o novo valor

def inserir_depois(lista, no_anterior, novo_dado):


assert no_anterior, "No anterior precisar existir na lista"
novo_no = no_lista(novo_dado)

novo_no.proximo = no_anterior.proximo

no_anterior.proximo = novo_no

lista = lista_encadeada() #criação da lista

print("Lista Vazia", lista)

insercao_novo_elemento(lista, 5)

no_anterior = lista.cabeca

inserir_depois(lista, no_anterior, 40)

print(lista)

Ebook Edinelson 16

Você também pode gostar