Você está na página 1de 144

unidade

Estrutura
DE DADOS
unidade

2
Estrutura de Dados - II
Prezado estudante,

Estamos começando uma unidade desta disciplina. Os textos que a compõem foram organizados com
cuidado e atenção, para que você tenha contato com um conteúdo completo e atualizado tanto quanto
possível. Leia com dedicação, realize as atividades e tire suas dúvidas com os tutores. Dessa forma,
você, com certeza, alcançará os objetivos propostos para essa disciplina.

OBJETIVO GERAL
• Compreensão da importância da aplicação da Estrutura de dados, apresentação dos
tipos de dados, uso de listas, listas sequenciais, encadeadas e dinâmicas

OBJETIVOS ESPECÍFICOS
• Identificar uma estrutura de dados.
• Reconhecer dados heterogêneos e homogêneos.
• Aplicar dados homogêneos (vetores e matrizes) e ponteiros.
• Identificar os softwares em camadas
• Compreender estrutura de dados
• Aplicar o uso de Pré e Pós condições
• Identificar o que é um Tipo Abstrato de Dados (TAD)
• Descrever como é criado um TAD.
• Reconhecer a criação de um TAD - Conjunto
• Reconhecer um TAD do tipo lista
• Descrever os elementos de uma lista
• Compor listas estáticas
• Identificar o funcionamento de uma lista (inserção, remoção, atualização e consulta
em qualquer ponto da lista).
OBJETIVOS ESPECÍFICOS
• Reconhecer como funcionam funções e procedimentos de uma lista (inserção,
remoção, atualização e consulta).
• Aplicar o uso de listas
• Identificar formas de armazenamento em uma lista

• Reconhecer encadeamento simples em uma lista


• Comparar lista encadeada com lista estática
• Reconhecer uma lista encadeada simples.
• Especificar operações de manipulação de uma lista encadeada simples.
• Identificar operações de acesso a uma lista encadeada simples
• Identificar o uso de uma lista encadeada dupla.
• Reconhecer a navegação em uma lista encadeada dupla para inserir, remover,
atualizar e consultar valores.
• Aplicar a implementação de listas encadeadas duplas.

• Declarar uma lista dinâmica.

• Construir funções de manipulação de uma lista dinâmica.

• Desenvolver funções de acesso a uma lista dinâmica


unidade

2
Parte 1

Estrutura de Dados

O conteúdo deste livro é


disponibilizado por SAGAH.
82

Estrutura de dados
Objetivos de aprendizagem
Ao final deste capítulo, você deve apresentar os seguintes aprendizados:

„ Identificar uma estrutura de dados.


„ Reconhecer dados heterogêneos e homogêneos.
„ Aplicar dados homogêneos (vetores e matrizes) e ponteiros.

Introdução
Para o profissional da área da Ciência da Computação, é importante
conhecer a forma como os dados são armazenados, organizados e mani-
pulados, pois essa atividade é uma das principais que são desenvolvidas
pelos sistemas computacionais.
Nesse sentido, a estrutura de dados é um elemento que vem, princi-
palmente na linguagem de programação C, para auxiliar na representação
e na abstração de estruturas mais complexas, executando operações
de armazenamento e busca de dados na memória, de maneira mais
sofisticada e robusta.
Neste capítulo, você vai estudar sobre estrutura de dados e dados
heterogêneos e homogêneos e sobre a aplicação de dados homogêneos,
como vetores e matrizes, e ponteiros.

A estrutura de dados
A área da Ciência da Computação trata diretamente com o armazenamento,
a organização, a manipulação e a utilização de dados e informações, por
isso, é importante entender como isso acontece. Estudar estruturas de dados,
principalmente na linguagem C, envolve (TENENBAUM; LANGSAM; AU-
GENSTEIN, 1995):
Estrutura de Dados - II UNIDADE 2
22 Estrutura de dados Estrutura de dados PARTE 1 83

„ A identificação e o desenvolvimento de entidades e operações que sejam


úteis e determinem quais tipos de problemas podem ser solucionados
pela sua utilização.
„ A determinação de representações para entidades abstratas.
„ A implementação de operações abstratas que possam ser utilizadas
sobre representações concretas.

Um dado é algo normalmente quantificável, o qual não tem um significado relevante


de maneira isolada.
O dado é considerado como o fundamento da informação. Conhecendo-se somente
o dado, dificilmente é possível chegar a um entendimento sobre o assunto tratado,
tomar decisões ou chegar a conclusões.
Já a informação consiste na ordenação e na organização dos dados, de maneira que
se torne possível compreender o seu significado, ou entendê-la dentro de um contexto.
Em outras palavras, a informação é o fruto do processamento dos dados, depois que
estes são analisados, interpretados de uma maneira pré-definida e qualificados.
O nosso conhecimento é oriundo da consolidação dos dados em forma de informa-
ção, logo, quanto mais um indivíduo se distancia dos dados, maior é a sua capacidade
de abstrair a realidade.

Quando são determinadas representações para entidades abstratas, é muito


importante que sejam observadas as especificações dos recursos disponíveis
para construir essas representações. Foi dito que essas características fazem
parte da estrutura de dados na linguagem C, pois muitas outras linguagens
já têm o conceito de estrutura de dados incorporados na sua estrutura. A sua
utilização pode até ser mais facilitada, mas nem sempre é eficiente.
A eficiência de uma estrutura de dados envolve, normalmente, variáveis,
como o tempo e o espaço. Se uma aplicação precisa manipular estruturas de
dados de forma muito intensa e repetida, a velocidade com que essas manipu-
lações são feitas será decisiva. Da mesma forma, uma aplicação que precisa
manipular uma grande quantidade de estruturas de dados, e tem um código
gigantesco para fazer a representação dessas estruturas, não será eficiente
(LAUREANO, 2008).
84 Estrutura de dados 23

A utilização de uma estrutura de dados serve, via de regra, para que os dados
que são vistos na vida real possam ser armazenados pelo computador, daí o
seu grau de abstração. As estruturas de dados envolvem o armazenamento de
dados organizados na memória de uma maneira mais sofisticada do que pela
utilização de variáveis básicas usadas em algoritmos simples. Quando se deseja
representar dados de forma direta, a referência a eles é feita normalmente por
meio de variáveis, mas quando se utiliza uma estrutura de dados, a referência
aos dados é feita normalmente por índices.

Quando o assunto é estrutura de dados, um índice é uma referência que se associa


a uma chave, a qual serve para otimizar a localização de um registro, quando é feita
uma consulta que envolve vários dados.

Uma estrutura de dados é um elemento que permite executar operações


e fazer a manipulação de dados. Ela serve para indicar como os dados são
representados e como se torna possível a sua manipulação. Um exemplo muito
comum para entender a estrutura de dados é a representação de um baralho
de cartas:

„ A representação das cartas pode ser feita por dois valores do tipo ca-
ractere, que são o naipe e o valor da carta.
„ As operações que podem ser feitas com as cartas são:
a) embaralhar todas as cartas;
b) comprar uma carta do topo do baralho;
c) retirar uma carta de um lugar qualquer do meio do baralho;
d) inserir uma carta na base do baralho.

Só é possível escolher o tipo de estrutura de dados que será utilizada na


aplicação depois de analisar e entender todos os tipos de operações que serão
possíveis de realizar com os dados, pois as estruturas de dados podem ser meios
elegantes de organizá-los, mas uma escolha errada pode trazer desvantagens,
principalmente de performance.
Estrutura de Dados - II UNIDADE 2
24 Estrutura de dados Estrutura de dados PARTE 1 85

As estruturas de dados servem para agrupar e manipular objetos dentro de


uma entidade que seja identificada por meio de um único nome de variável.
Normalmente, a estrutura de dados é formada por variáveis de tipos diferentes,
as quais são chamadas de membros, elementos ou campos da estrutura.
A declaração de uma estrutura de dados normalmente é feita pela sua
nomeação e pela indicação dos campos que farão parte dela, como o tipo e
o nome das variáveis. Algumas observações importantes sobre a declaração
da estrutura de dados são:

„ A chave que fecha a declaração da estrutura de dados (struct) deve ser


seguida de um ponto-e-vírgula.
„ Não é possível que mais de um campo tenha o mesmo nome.

Essa é a forma de declarar uma estrutura de dados na linguagem de pro-


gramação C:

struct nome_da_estrutura {
tipo_do_campo1 nome_do_campo1;
tipo_do_campo2 nome_do_campo2;
tipo_do_campo3 nome_do_campo3;
...
};

Com base na declaração acima, este é um exemplo de declaração de es-


trutura de dados em C:

struct boletim (
char nome_do_aluno(50);
char nome_disciplina(50);
int qtd_faltas;
float nota1;
float nota2;
float nota_exame;
);
86
Estrutura de dados 25

Dados heterogêneos e homogêneos


Quando uma estrutura de dados armazena elementos de tipos diferentes, é
dito que esta é uma estrutura de dados heterogênea. Normalmente, esse tipo
de dado é chamado de registro, então, o registro é uma estrutura de dados
que faz o agrupamento de dados de tipos diferentes entre si. Ele é formado
por uma quantidade determinada de campos, os quais são itens individuais
de dados e relacionados de forma lógica (LAUREANO, 2008).
Em outras palavras, um registro é algo que agrupa elementos que não são
do mesmo tipo de dado, mas que têm vínculo lógico. Os registros consistem
em conjuntos de posições de memória, os quais são identificados pelo mesmo
nome e são individualizados por meio de identificadores que se associam a
cada conjunto de posições (Figura 1).

Figura 1. Representação gráfica de um registro.


Fonte: Laureano (2008, p. 41).
Estrutura de Dados - II UNIDADE 2
26 Estrutura de dados Estrutura de dados PARTE 1 87

Para referenciar um único campo dentro de um registro, é preciso utilizar


essa sintaxe:

nome_da_estrutura[índice].nome_do_campo;

Por sua vez, uma estrutura de dados que armazena somente um tipo de dado
é conhecida, então, como dados homogêneos. Os elementos que compõem
uma estrutura de dados homogênea correspondem às posições de memória,
as quais são identificadas por meio de um mesmo nome, individualizadas por
índices que são todos dos mesmos tipos de dados. Os dados homogêneos são
representados pelos vetores, ou estruturas de dados unidimensionais, e pelas
matrizes, que são estruturas de dados bidimensionais (LAUREANO, 2008).

Vetores
Os vetores são estruturas de dados unidimensionais lineares e, por isso, pre-
cisam de um único índice para fazer o endereçamento e para percorrer toda
a estrutura. Um vetor é uma estrutura de dados utilizada para fazer o arma-
zenamento de uma lista de valores do mesmo tipo, ou seja, em uma mesma
variável, vários valores de mesmo tipo são armazenados.
Quando um vetor é definido, é declarada uma quantidade fixa de posições
que ele deve ter, ou seja, um vetor é um elemento que será dividido em várias
posições que serão entendidas e reconhecidas pelo computador. Cada uma
dessas posições vai ser responsável por armazenar um único valor do vetor e
cada uma delas será reconhecida por um índice, ou endereço, e será por ele que
essa posição será encontrada e poderá ser referenciada. Logo, apesar de essa
estrutura ser de somente um tipo de dado, ela terá vários valores diferentes
do mesmo tipo.
Uma estrutura de dados do tipo vetor tem as seguintes características
(DEITEL; DEITEL, 2011):

„ É alocado de forma estática, ou seja, no momento da sua declaração,


deve-se conhecer o tamanho ou a quantidade de posições que ele terá.
„ É uma estrutura de dados homogênea, formada por elementos com o
mesmo tipo de dado.
„ Cada posição do vetor contém somente um valor.
„ Os tamanhos dos valores de cada posição, por serem do mesmo tipo,
são iguais.
„ Faz a alocação dos dados de forma sequencial (Figura 2).
88
Estrutura de dados 27

Figura 2. Representação gráfica de um vetor.


Fonte: Laureano (2008, p. 27).

A sintaxe para a definição do vetor acima seria:

tipo_de_dado nome_do_vetor[quantidade_de_posicoes_do_vetor]

Em C:

float nota[5];

O funcionamento de um vetor consiste em determinar a localização de


todos os seus elementos, partindo do endereço do primeiro elemento, o que se
torna possível porque todos estes ficam dispostos lado a lado e cada elemento
tem um tamanho fixo. É importante lembrar que a primeira posição de um
vetor será sempre conhecida por 0 e nunca por 1.

nota[0] = 9.5;
nota[1] = 7.4;
nota[2] = 8.1;
nota[3] = 4.6;
nota[4] = 4.5;

Matrizes
As matrizes são estruturas de dados bidimensionais, os quais precisam de dois
índices para fazer o endereçamento e para percorrer toda a estrutura: um que
servirá para referenciar a linha e outro que servirá para referenciar a coluna
da matriz (TENENBAUM; LANGSAM; AUGENSTEIN, 1995).
Estrutura de Dados - II UNIDADE 2
28 Estrutura de dados Estrutura de dados PARTE 1 89

Assim como os vetores, as matrizes têm algumas características:

„ são alocadas de forma estática, ou seja, no momento da sua declaração,


deve-se conhecer o tamanho que elas terão;
„ são uma estrutura de dados homogênea, a qual é formada por elementos
com o mesmo tipo de dados;
„ cada posição da matriz contém somente um valor;
„ os tamanhos dos valores de cada posição, por serem do mesmo tipo,
são iguais;
„ fazem a alocação dos dados de forma sequencial (Figura 3).

Figura 3. Representação gráfica de uma matriz.


Fonte: Laureano (2008, p. 31).

Uma matriz envolve dois ou mais vetores, os quais são definidos por um
conjunto de elementos, ou seja, cada dimensão da matriz é formada por um
vetor. A primeira dimensão de elementos é considerada o primeiro vetor, a
segunda é considerada o segundo vetor, a terceira dimensão de elementos é
considerada o terceiro vetor, e assim por diante.
A sintaxe para a definição da matriz acima seria:

tipo_de_dado
nome_da_matriz[quantidade_de_linhas][quantidade_de_colunas]
90 Estrutura de dados 29

Em C:

char letras[3][6];

A alocação de valores para os elementos da matriz pode ser feita linha


por linha ou coluna por coluna. É importante lembrar, da mesma forma que
os vetores, que a primeira posição de cada dimensão da matriz será sempre
conhecida por 0 e nunca por 1.

letras[0][0] = “M”;
letras[0][1] = “A”;
letras[0][2] = “R”;
letras[0][3] = “C”;
letras[0][4] = “O”;
letras[0][5] = “S”;
letras[1][0] = “N”;
letras[1][1] = “A”;
letras[1][2] = “S”;
letras[1][3] = “S”;
letras[1][4] = “E”;
letras[1][5] = “R”;
letras[2][0] = “D”;
letras[2][1] = “O”;
letras[2][2] = “N”;
letras[2][3] = “A”;
letras[2][4] = “L”;
letras[2][5] = “D”;

Aplicação de dados homogêneos (vetores e


matrizes) e ponteiros
Existem muitas operações que podem ser feitas com vetores e matrizes na
linguagem de programação C e as mais básicas serão exibidas a seguir.
Para que se possa compreender a aplicação de um vetor, pode-se criar um
arquivo em C com o nome vetor.cpp, cujo código será o seguinte:
30 Estrutura de dados Estrutura de Dados - II UNIDADE 2
Estrutura de dados PARTE 1 91

Uma das maneiras mais fáceis de incluir elementos em um vetor é utilizando


o laço for, o que é feito entre as linhas 10 e 12 do código acima.
Depois disso, o código do programa exibe os valores contidos no vetor, nas
linhas 14 a 16, e exibe o vetor ao contrário entre as linhas 18 e 20.
Ainda utilizando o laço for, mas agora fazendo um teste com cada posição
do vetor, são exibidos os elementos pares nas linhas 22 a 25.
92

Estrutura de dados 31

Finalizando, nas linhas 27 a 31, é exibido o maior elemento do vetor, atri-


buindo cada valor de posição a uma variável, a qual recebe um valor maior
cada vez que o teste feito é verdadeiro.
A execução do código acima exibirá uma tela semelhante à da Figura 4.

Figura 4. Execução do código.

Para que se possa compreender a aplicação de uma matriz, pode-se criar


um arquivo em C com o nome matriz.cpp, cujo código será o seguinte:
Estrutura de Dados - II UNIDADE 2
Estrutura de dados PARTE 1 93
32 Estrutura de dados

Como a matriz é formada de vários vetores, mas tem mais de uma dimensão,
uma das melhores maneiras de inserir elementos em uma matriz é utilizar
laços de for encadeados, nos quais um faz a varredura nas posições da linha e
outro faz a varredura nas posições da coluna. Entre as linhas 11 e 16, o código
faz a inserção de valores nas posições da matriz.
Logo a seguir, nas linhas 18 a 24, são utilizados laços de for encadeados,
novamente, para fazer a exibição do valor contido em cada uma das posições
da matriz.
Finalizando, entre as linhas 26 e 34 está o código utilizado para verificar
qual é o maior elemento da matriz. Dessa forma, novamente são utilizados
laços de for encadeados, mas, para isso, é feito um teste para cada um dos
valores das posições para verificar se estes são maiores do que uma variável,
a qual foi inicializada com 0, mas recebe um valor maior, caso seja encontrado
(Figura 5).
94
Estrutura de dados 33

Figura 5. Exemplo de operações com matriz.

Ponteiros
Um ponteiro é um tipo de dado que se diferencia de uma variável, no sentido
de que a variável faz uma referência direta a um valor. Já o ponteiro faz uma
referência indireta a um valor. Quando se faz a modificação do valor de um
ponteiro, está sendo modificado o valor da variável para a qual o ponteiro está
apontando. Em outras palavras, o ponteiro é um tipo de dado que permite
referenciar a posição de um objeto na memória, mas também o próprio objeto
(DEITEL; DEITEL, 2011).
Quando se trabalha com ponteiros, o operador unário * é utilizado para
acessar o conteúdo da variável para o qual o ponteiro está apontando, enquanto
o operador unário & é utilizado para acessar o endereço da variável para o
qual o ponteiro está apontando.
É importante lembrar que cada ponteiro deve ser declarado conforme o
tipo de dado da variável para a qual ele vai apontar e que a declaração de um
ponteiro é feita ao colocar um * na frente da variável:
Estrutura de Dados - II UNIDADE 2
34 Estrutura de dados Estrutura de dados PARTE 1 95

No código acima, é feita a atribuição de um valor para uma variável. Depois,


um ponteiro vai fazer a referência para essa variável, o que possibilita exibir
o seu valor e o seu endereço.
A execução do código exibe uma tela semelhante à apresentada na Figura 6.

Figura 6. Exemplo de declaração de ponteiro.

É possível também fazer operações de soma e subtração com uma vari-


ável do tipo ponteiro e, nesse caso, será somada ou diminuída, no ponteiro,
a quantidade de endereços de memória que é relativa ao tipo de dado que o
ponteiro armazena (LAUREANO, 2008).
De maneira resumida, se um ponteiro que armazena um int ocupa 4 bytes,
cada operação de soma feita no ponteiro vai acrescentar 4 posições ou unida-
des de memória. Já se o ponteiro armazenar um char, o qual ocupa 1 byte de
memória, cada operação de soma feita no ponteiro vai acrescentar 1 posição
ou unidade de memória. O exemplo abaixo ilustra essa explicação:
96 Estrutura de dados 35

A execução desse código vai retornar a uma tela semelhante à da Figura 7.

Figura 7. Exemplo de aritmética de ponteiro.


36 Estrutura de dados

DEITEL, P. J.; DEITEL, H. M. Como programar em C. 6. ed. São Paulo: Pearson, 2011.
LAUREANO, M. Estrutura de dados com algoritmos e C. São Paulo: Brasport, 2008.
TENENBAUM, A. A.; LANGSAM, Y.; AUGENSTEIN, M. J. Estruturas de dados usando C.
São Paulo: Makron Books, 1995.
PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 2

Tipos Abstratos de Dados 1

O conteúdo deste livro é


disponibilizado por SAGAH.
100 ESTRUTURA DE DADOS

Tipos abstratos de dados


Objetivos de aprendizagem
Ao final deste capítulo, você deverá apresentar os seguintes aprendizados:

 Identificar o que é um tipo abstrato de dados (TAD).


 Descrever como é feita a criação de um TAD.
 Reconhecer a criação de um TAD conjunto.

Introdução
Na área da ciência da computação, os tipos de dados e as estruturas de
dados são utilizados pelos programas para armazenar informações por
meio de operações específicas escritas em linguagem de programação.
Para quem desenvolve programas de computação, é muito mais simples
quando se pode trabalhar com as estruturas de dados por meio das
operações que elas podem executar, e não com a maneira como elas
são implementadas. Quando isso é possível, fica configurado um tipo
abstrato de dados (TAD).
Neste capítulo, você estudará o que é TAD, como fazer a sua criação
e como fazer a criação de um TAD conjunto.

Tipo abstrato de dados


Para que seja possível falar de TAD, é importante que você conheça dois
conceitos: tipo de dados e estrutura de dados (BACKES, 2016).

 Tipo de dados: é um termo utilizado nas linguagens de programação


que diz respeito ao tipo de dado de uma variável, constante ou função.
Isso equivale a dizer o tipo de valores que uma variável, constante
ou função pode armazenar, receber ou devolver. Char, int e float são
exemplos de tipos de dados da linguagem de programação C.
 Estrutura de dados: na área da ciência da computação, uma estrutura
de dados é uma maneira particular de armazenar e organizar dados com
Estrutura de Dados - II UNIDADE 2
2 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 101

o objetivo de que sejam resgatados e utilizados do modo mais eficiente


possível. Os tipos estruturados de dados são exemplos de estruturas
de dados, que vêm predefinidas na linguagem de programação, mas
também podem ser definidas pelo programador. Vetores, registros e
listas encadeadas são exemplos de estruturas de dados.

Os tipos de dados e as estruturas de dados são utilizados pelo programa


para armazenar as informações por meio de operações específicas escritas em
linguagem de programação. Para o programador, pode ser mais interessante
trabalhar com as estruturas de dados pelas operações suportadas por elas, e
não pela maneira como é feita a sua implementação. Quando uma estrutura
de dados é definida dessa maneira, ela configura um TAD.
O TAD envolve a especificação de um conjunto de dados, e das operações
que podem ser executadas com esses dados, ou seja, o TAD é um tipo de dados
definido pelo seu comportamento, e não pela sua representação. Ele exige
que as operações possíveis para os dados sejam definidas sem que estejam
vinculadas a uma representação. Dessa forma, um programador não precisa
necessariamente saber como os tipos de dados char, int ou float funcionam
ou são representados internamente, ele só precisa saber o tipo de operações
que podem ser feitas com eles, e acessá-los apenas por meio das operações
que eles suportam. Esse tipo de conceito é suportado por algumas linguagens
de programação do tipo procedimental, como o C.
Veja algumas características que são típicas dos TAD:

 é caracterizado pela separação entre a sua definição conceitual e a


implementação propriamente dita;
 só é acessado pelo programa por meio de suas operações, pois a sua
estrutura de dados nunca é acessada diretamente;
 o programador tem acesso somente a uma descrição dos valores e das
operações que são suportados pelo TAD;
 o programador não tem acesso à implementação do TAD, pois ela é
invisível ou inacessível, ou seja, está encapsulada ou escondida.

A premissa principal do TAD é desvincular o tipo de dado, que são os


valores que ele suporta e as operações que podem ser feitas com ele, da sua
implementação, isto é, quando um TAD é definido, o programador precisa se
preocupar com o que ele faz, e não com a maneira como ele faz.
102 ESTRUTURA DE DADOS
Tipos abstratos de dados 3

Além das características dos TAD, podem ser identificadas algumas van-
tagens na sua utilização, conforme você pode ver a seguir (VAREJÃO, 2015).

 Reutilização: uma vez que o TAD tenha sido definido, implementado e


testado, verificando-se que funciona corretamente e do modo esperado,
ele pode ser acessado de diferentes partes do mesmo programa ou de
programas diferentes.
 Manutenção facilitada: uma vez que mudanças feitas na implementação
do tipo TAD não vão influenciar o código dos programas que o utilizam.
 Código do programa: utiliza os detalhes da implementação do TAD
e é minimizado, o que dá maior liberdade para que o programa seja
alterado com o mínimo de custo e esforço.
 Segurança: o programador não tem acesso direto aos dados, o que evita
que eles sejam manipulados de maneira incorreta.
 Encapsulamento: o conjunto de operações possíveis para o TAD é tudo
o que um programador precisa saber sobre ele, sem que seja necessário
nenhum conhecimento técnico para que ele seja implementado.

O TAD nada mais é do que um conjunto de valores que tem o seu com-
portamento definido por meio de operações que são implementadas em forma
de funções. Um TAD é construído a partir de tipos básicos de dados, como
o char, o int e o double, mas também pode ser construído a partir de tipos
estruturados, como o array, o struct e o union.
Nesse sentido, os TAD são elementos teóricos, que são usados para sim-
plificar a maneira de descrever algoritmos sobre coisas abstratas, pois, para
que um TAD seja criado, é fundamental que alguns dados sejam ocultados do
programador, como a sua implementação, que deve ser totalmente invisível.
Dessa forma, o TAD funciona como uma espécie de caixa-preta para o
programador, que jamais tem acesso direto às informações que se encontram
armazenadas nele, uma vez que a sua implementação se encontra desconectada
da sua utilização, pois, novamente, quando se define um TAD, a preocupação é
com o que ele é capaz de fazer, e não com a maneira como as coisas são feitas.
Um TAD especifica tudo o que é necessário saber sobre um tipo de dado
específico, mas não faz referência à forma como ele foi implementado, mas
às operações possíveis para as quais ele possa ser utilizado.
Os sistemas que utilizam TAD ficam divididos em programas que utilizam
o TAD, chamados de clientes ou interfaces, e programas que definem a sua
Estrutura de Dados - II UNIDADE 2
4 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 103

estrutura e o seu comportamento, chamados de implementação. O módulo de


interface contém a declaração das funções que correspondem às operações
suportadas pelo TAD e é visível para o programador. Um TAD pode, então, ser
definido como a união de uma estrutura de dados e das operações definidas
para serem feitas com esses dados. Observe o esquema de um TAD na Figura 1.

TAD
Operações

Criar

Destruir
Programa do
Dados
Usuário
Atualizar

Consultar

Figura 1. Esquema de um TAD.


Fonte: Adaptada de Backes (2016).

Criação de um tipo abstrato de dados


Quando se define um TAD, é necessário ter em mente que uma boa prática é
fazer a modularização do código do programa, o que equivale a dizer que na
linguagem de programação C, por exemplo, é preciso criar dois arquivos de
programa para que um TAD seja implementado (PIVA JUNIOR et al., 2014):

 Arquivo .H: contém os protótipos das funções, os tipos de ponteiros,


e todos os dados que forem acessados de maneira global ao longo do
programa (parte conceitual).
 Arquivo .C: contém a declaração dos tipos de dados e ainda a im-
plementação de todas as funções suportadas pelo TAD (parte de
implementação).
104 ESTRUTURA DE DADOS Tipos abstratos de dados 5

Esses dois arquivos devem ter o mesmo nome, o que vai mudar entre eles
é somente a extensão, que será .H ou .C. Dessa maneira, é feita a separação
entre a parte da definição do TAD e a parte que faz a implementação dele.
Para entender melhor como é feita a criação de um TAD, podemos usar
o exemplo de um TAD para transações em contas correntes bancárias. Para
que esse exemplo seja implementado, é necessário dividir o código em três
programas: o primeiro funcionará como o programa principal, o segundo
conterá os protótipos das funções e o terceiro conterá a declaração das funções.
Os códigos dos programas do exemplo são apresentados a seguir.

Código do arquivo transacao.h:

Nas linhas 1 a 5 do código apresentado, é feita a declaração do TAD Conta,


que vai armazenar dados de contas correntes de clientes, com informações de
nome do cliente, número da conta corrente e saldo da conta.
Das linhas 7 a 20 são feitas as declarações das funções que contêm as
operações possíveis com o TAD Conta: criação da conta, depósito em conta,
saque da conta, transferência para a conta e impressão do extrato da conta.
Estrutura de Dados - II UNIDADE 2
6 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 105

Código do arquivo transacao.c:


106 ESTRUTURA DE DADOS
Tipos abstratos de dados 7

Nas linhas 1 a 3 do código apresentado, é feita a inclusão das bibliotecas do


C, necessárias para a execução do programa, incluindo o arquivo transacao.h,
definido pelo programador.
Das linhas 5 a 45, é feita a implementação das funções, que correspondem
às operações possíveis com o TAD Conta. A função criar cria as contas cor-
rentes de acordo com os parâmetros recebidos; a função depositar aumenta o
valor do saldo da conta corrente; a função sacar verifica se é possível efetuar
o saque, dependendo do saldo da conta corrente; a função transferir verifica
se é possível transferir um determinado valor de uma conta para outra, em
virtude do saldo da conta de origem; e a função extrato imprime as informa-
ções do TAD Conta.

Código do arquivo conta.c:


Estrutura de Dados - II UNIDADE 2
8 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 107

Na linha 1 do código apresentado, é feita a inclusão do arquivo transacao.c,


definido pelo programador.
Na função main, das linhas 5 a 11, são criadas as contas correntes, passando
nomes de clientes, números de contas correntes e valores para os saldos das
contas correntes.
Das linhas 13 a 31 são feitas transações bancárias entre as contas correntes
e o seu extrato é impresso na tela imediatamente após a efetivação dessas
transações. A execução do programa apresenta a tela ilustrada na Figura 2.

Figura 2. Exemplo de criação de TAD.


108 ESTRUTURA DE DADOS
Tipos abstratos de dados 9

Criação de um tipo abstrato de dados conjunto


Um TAD conjunto, também chamado de set, é uma coleção de elementos em
que cada um é um conjunto, ou um elemento primitivo, que pode ser chamado
de átomo. É importante observar que, dentro de um TAD conjunto, todos
os membros são diferentes entre si, ou seja, nenhum conjunto possui dois
elementos iguais (PIVA JUNIOR et al., 2014).
É possível realizar várias operações por meio da utilização de conjuntos, como
a união, a interseção, a diferença, a inserção e a remoção de elemento, além de
encontrar o elemento máximo, entre outras. O conjunto é representado por uma
lista que não contém itens repetidos e que contém os elementos do conjunto.
Para exemplificar as operações que podem ser realizadas entre conjuntos,
pode-se implementar o código em três programas, conforme apresentado a seguir.

Código do arquivo principal.c:


Estrutura de Dados - II UNIDADE 2
Tipos Abstratos de Dados 1 PARTE 2 109
10 Tipos abstratos de dados

Na linha 1 do código apresentado, é feita a inclusão do arquivo conjunto.c.


Logo depois, já na função main, das linhas 4 a 22, é feita a criação, a inicia-
lização e a inserção de valores nos conjuntos A e B. O conjunto C fica vazio,
pois vai receber o resultado das operações entre os conjuntos A e B.
Das linhas 24 a 46 são feitas as chamadas das funções que executam as
operações entre os conjuntos: retirada de elemento, inserção de elemento,
interseção entre os conjuntos A e B, união entre os conjuntos A e B e locali-
zação de valor em um determinado conjunto.
110 ESTRUTURA DE DADOS
Tipos abstratos de dados 11

Código do arquivo conjunto.h:

Na linha 1 do código apresentado, a diretiva de pré-processamento define


MAX como 10. Logo depois, são definidos os TAD Elemento e Conjunto.
Das linhas 12 a 34 é feita a prototipação das funções que guardam as
operações permitidas para os TAD: criação, inicialização, inserção, remoção,
interseção, união, busca e impressão.
Estrutura de Dados - II UNIDADE 2
12 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 111

Código do arquivo conjunto.c:


112 ESTRUTURA DE DADOS Tipos abstratos de dados 13
Estrutura de Dados - II UNIDADE 2
14 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 113
114 ESTRUTURA DE DADOS
Tipos abstratos de dados 15

Das linhas 1 a 3 do código apresentado, é feita a inclusão das bibliotecas


C e do arquivo .H, necessários para a execução do programa.
Das linhas 5 a 33, são implementadas as funções que servem para fazer a
criação, a inicialização dos conjuntos com 0 e a inserção dos valores passados
pela função main() nos conjuntos.
Das linhas 35 a 43 é implementada a função que faz a operação de remoção
de um elemento do conjunto.
Das linhas 45 a 78 é feita a implementação da função que faz a operação
de interseção entre os conjuntos A e B, mostrando ainda quantos valores se
encontraram repetidos entre os dois conjuntos.
Estrutura de Dados - II UNIDADE 2
16 Tipos abstratos de dados Tipos Abstratos de Dados 1 PARTE 2 115

Das linhas 80 a 122 é implementada a função responsável pela operação


de união entre os conjuntos A e B, e, novamente, o conjunto C é quem recebe
o resultado da operação.
Das linhas 124 a 134 é feita a implementação da função buscar, que serve
para encontrar um determinado valor no conjunto e mostrar a posição em
que ele se encontra.
Por fim, a função imprimir mostra o conjunto específico, passado por
parâmetro pela função main().
A execução do programa apresenta a tela ilustrada na Figura 3.

Figura 3. Exemplo de criação de TAD conjunto.

BACKES, A. Estrutura de dados descomplicada em linguagem C. Rio de Janeiro: Elsevier,


2016.
PIVA JUNIOR, D. et al. Estrutura de dados e técnicas de programação. Rio de Janeiro:
Elsevier, 2014.
VAREJÃO, F. M. Introdução à programação: uma nova abordagem usando C. Rio de
Janeiro: Elsevier, 2015.
PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 3

Tipos Abstratos de Dados 2

O conteúdo deste livro é


disponibilizado por SAGAH.
118 ESTRUTURA DE DADOS

Tipos abstratos de dados


Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

„ Identificar os softwares em camadas.


„ Determinar estrutura de dados.
„ Aplicar o uso de pré e pós-condições.

Introdução
Neste capítulo, você vai estudar e compreender sobre as principais estru-
turas de dados, estas que são de extrema importância para o desenvol-
vimento de sistemas (software). Se bem utilizadas, as estruturas auxiliam
na otimização e na organização dos dados, para que estes possam ser
utilizados eficientemente. Além de compreender as estruturas de dados,
veremos também como podemos dividi-los em diferentes camadas,
fazendo com que o código continue legível em longo prazo.
Vamos imaginar o desenvolvimento de um sistema de médio porte
hoje. Será que daqui a 10 anos você se lembrará o que ou como desen-
volveu/programou algo feito 10 anos atrás? Por esse e outros motivos
que precisamos entender e compreender o conceito sobre estrutura
de dados e, de certa forma, saber desenvolver e identificar um software
separado em camadas.

Desenvolvimento de software em camadas


Vivemos em um mundo cada vez mais dependente da tecnologia. Com o
surgimento e a rápida popularização dos smartphones com acesso à Internet,
ficamos sedentos por aplicativos e soluções para nosso dia a dia. Nas empresas,
há cada vez mais processos manuais sendo automatizados, com isso, surgem
robustos sistemas, que vão desde o processamento do pedido do cliente, até
as estratégias de relacionamento com este, além de relatórios elaborados e
ferramentas que auxiliam os gestores nas tomadas de decisão.
Estrutura de Dados - II UNIDADE 2
2 Tipos abstratos de dados Tipos Abstratos de Dados 2 PARTE 3 119

Nesse contexto, o profissional que desenvolve esses sistemas, do aplica-


tivo mais simples ao sistema mais complexo, precisa estudar e se aprimorar
para desenvolver sistemas que não apenas automatizam o processo, mas que
também tenham um bom desempenho, que tenham uma interface amigável
para o usuário, que possam ser atualizados com praticidade e rapidez, entre
outros aspectos.
Ao longo do tempo, os desenvolvedores foram criando padrões mais efi-
cazes e eficientes, de modo que estes facilitassem a criação de softwares
complexos, sendo assim, uma equipe grande poderia se dividir e cada um faria
uma parte, ou então que o sistema pudesse ser criado em etapas que fossem
se complementando e conversando entre si.
Uma característica comum na maioria desses padrões que foram sendo
desenvolvidos é a separação do software em camadas. Praticamente todo
sistema coleta dados e solicitações do usuário, manipula esses dados de al-
guma forma e os armazena, em forma de relatório ou gráfico, por exemplo,
para que possam ser lidos mais tarde. Então, a ideia principal seria que cada
camada fosse responsável por uma dessas etapas. Conforme o tamanho e a
complexidade do sistema, novas camadas podem ser criadas, mas, em geral,
as principais e mais comuns seriam: interface, negócio, persistência e dados.

 Interface: mecanismos do sistema que permitem que o usuário insira


informações ou acione comandos, são as telas do programa. Essa camada
envia comunicação para a camada de negócio.
 Negócio: processamento dos dados. São as regras do negócio, as in-
formações que o sistema irá trazer, a forma como as mostramos e as
funcionalidades que estarão disponíveis para o usuário. O que o usuário
pode ou não pode fazer no sistema.
 Persistência: responsável por manipular os dados, acessando e enviando
para a camada de dados. Quanto maior o volume de dados, mais ela-
borada deve ser a lógica de armazenamento e consulta. Essa camada é
uma ponte entre as camadas de negócios e dados.
 Dados: armazenamento dos dados em servidores e sistemas de geren-
ciamento de banco de dados.
120 ESTRUTURA DE DADOS

Tipos abstratos de dados 3

Um sistema também pode coletar dados de outros sistemas, ou também de dispositivos,


não somente do usuário. Como exemplo, podemos citar um aplicativo que mostra a
temperatura local, pois essa temperatura não é informada pelo usuário, ela provém
de equipamentos das estações meteorológicas.

Vantagens da separação do software em camadas


Embora existam vários padrões de projeto que aplicam a separação em cama-
das, a utilização desse conceito traz inúmeras vantagens, que vamos elencar
a seguir.

 Facilidade de trabalho em equipe: isso se deve ao fato de estabelecer


um vocabulário comum entre o time de desenvolvedores. De certa
forma, reduz o tempo do projeto, até porque um ou mais módulos do
sistema podem ser reutilizados, entre outras vantagens que podem ser
visualizadas em um trabalho de equipe.
 Reuso de código: muitas rotinas de um sistema se repetem em diversas
aplicações, como inserir, excluir, atualizar e consultar. Imagine então
que você criou um módulo que já tenha todas essas rotinas prontas,
aprimoradas e testadas. Dessa forma, basta incluir no novo projeto e se
concentrar nas particularidades deste que precisam ser desenvolvidas.
 Facilidade de manutenção: a separação em camadas evita a repetição de
código, pois, se você tem um módulo que é responsável por uma rotina,
sempre que precisar executá-la, você a aciona, não sendo necessário
reescrever todos os comandos novamente. Dessa forma, quando for
necessário atualizar, você fará isso em uma única parte do código e todas
as funcionalidades que utilizam essa rotina já ficarão atualizadas também.
 Integração contínua: cada parte de um time de desenvolvimento pode
agir em uma determinada parte do sistema/software, fazendo com que
a progressão seja muito mais ágil.
 Teste do software: os testadores poderão realizar o seu trabalho de modo
que seja possível separar as baterias de testes, atingindo cada camada
do sistema, como, por exemplo, desenvolver classes de testes somente
para a camada de persistência ou desenvolver classes de testes somente
para a camada de interface e assim por diante.
Estrutura de Dados - II UNIDADE 2
4 Tipos abstratos de dados Tipos Abstratos de Dados 2 PARTE 3 121

Introdução às estruturas de dados


Tendo em vista o grande volume de dados que os softwares precisam manipular
atualmente, é necessário estudar e aprimorar cada vez mais o armazenamento
e a organização desses dados, para que as diferentes tecnologias existentes
possam tirar o melhor proveito deles.

Para onde vão os dados?


Quando se trata de armazenamento de dados, temos dois momentos: o ar-
mazenamento temporário, quando os dados estão sendo manipulados ou
processados, e o armazenamento permanente, no qual os dados ficam até
serem requisitados pelo sistema.
O armazenamento permanente se dá, normalmente, em sistemas de ge-
renciamento de banco de dados (SGBD) ou arquivos de textos mais simples
(depende do tipo de sistema e de como essas informações precisam ser arma-
zenadas, se é necessário maior segurança ou maior velocidade de acesso, se
o volume é grande ou pequeno, entre outras características). Aqui, o armaze-
namento é feito em disco rígido, ou seja, no HD.
O HD, porém, como tem uma grande capacidade de armazenamento, possui
uma velocidade de acesso menor. Por isso há a memória de trabalho, também
conhecida como memória RAM (random access memory). Para manipular
dados, o sistema busca do SGBD e carrega para a memória RAM, pois a co-
municação do processador para com ela é muito mais rápida do que com o HD.
Porém, apesar de ser mais rápida, a capacidade de armazenamento da
memória RAM é muito menor, assim o sistema precisa prever que tipo de dado
precisará manipular para saber quanto de memória será necessário reservar
para poder executar as tarefas. Quanto mais correta for essa previsão, melhor
será o desempenho. Damos o nome de variáveis a esses espaços reservados
na memória para guardar dados temporariamente.

Os tipos de dados
Para criar variáveis, as linguagens oferecem uma série de tipos de dados, que
costumam ser bastante parecidas, apesar de variarem em pequenos detalhes
ou intervalos. Em resumo, podemos separar os dados em números inteiros,
números reais, caracteres ou valores lógicos (verdadeiro ou falso).
122 ESTRUTURA DE DADOS
Tipos abstratos de dados 5

Vejamos no Quadro 1 os tipos de dados disponíveis na linguagem C.

Quadro 1. Tipos de dados primitivos em C.

Char Guarda um caractere (número inteiro


de -128 a 127, letra ou símbolo),
ocupando 1 byte de memória

Int Guarda um número inteiro, na faixa de


-2.147.483.648 a 2.147.483.647, ocupando bytes

Float Números reais (ponto flutuante) de


precisão simples (seis casas decimais),
na faixa de 3.4 E-38 a 3.4E+38

double Números reais (ponto flutuante) de precisão


dupla (dezesseis casas decimais), na faixa de
3.4E-4932 a 1.1E+4932, ocupando 8 bytes

Fonte: Silva e Oliveira (2014).

Como pode ser observado, a linguagem C não tem um tipo lógico.

Uso da memória: alocação estática versus alocação


dinâmica
A alocação estática de memória ocorre no momento da compilação do pro-
grama, ou seja, quando o software é colocado em execução. O sistema lê as
variáveis que foram definidas e reserva a memória para elas, que só serão
liberadas para outras aplicações quando o programa for fechado. Isso signi-
fica que a alocação e a liberação da memória são controladas pelos próprios
mecanismos da linguagem.
Já a alocação dinâmica ocorre no momento em que seu uso se torna necessário,
durante a execução do programa. Se a rotina que utiliza algum tipo de estrutura
dinâmica não for acionada, a memória não será reservada. Nesses casos, a alo-
cação é controlada por meio de comandos/funções que permitem tanto alocar,
Estrutura de Dados - II UNIDADE 2
6 Tipos abstratos de dados Tipos Abstratos de Dados 2 PARTE 3 123

quanto liberar a memória. Utilizamos esse tipo de alocação quando não temos
como prever a quantidade de dados que serão manipulados pelo programa.
Por exemplo, imaginemos que estamos desenvolvendo um programa que
coletará as respostas de uma pesquisa e o pesquisador não sabe quantas pes-
soas ele conseguirá entrevistar no dia. Então, para cada nova resposta que
precisarmos armazenar, alocamos um novo espaço na memória.

As estruturas de dados
Podemos separar os tipos de dados manipulados pelos softwares em dois
grupos: atômicos ou compostos.
Um dado atômico é aquele que podemos considerar indivisível, ou seja,
que não podemos separar em partes. Exemplos: a idade de uma pessoa e o
percentual de desconto. Já os dados compostos são aqueles que são formados
por um conjunto de dados atômicos, como, por exemplo, uma data, que é
composta por dia, mês e ano.
Para manipular os dados compostos, temos as estruturas de dados, que
consistem em relacionar, logicamente, um conjunto de dados, com o objetivo
de resolver problemas com maior rapidez e produtividade e com melhor de-
sempenho. Vamos conhecer as principais estruturas de dados a seguir.

Vetores
Um vetor é uma estrutura de dados unidimensional que armazena uma de-
terminada quantidade de dados de um mesmo tipo e em uma mesma variável
de forma sequencial. Essa variável é organizada em índices que servem para
endereçar os dados. Cada índice aponta para uma posição no vetor, e cada
posição consegue armazenar um único dado.
No ato da declaração de um vetor, deve ser especificado o tipo de dado e a
quantidade de índices que ele conterá. Por exemplo, se declararmos um vetor
do tipo int com 5 posições chamado de valores, conseguimos armazenar nele 5
valores diferentes do tipo inteiro, cada um em uma posição. A alocação de um
vetor é estática, ou seja, na execução do programa será reservado, na memória,
um espaço para a quantidade de dados que definirmos, mesmo que nem todas
as posições sejam utilizadas. A Figura 1 mostra a representação de um vetor.
124 ESTRUTURA DE DADOS
Tipos abstratos de dados 7

Figura 1. Representação gráfica de um vetor.

Matrizes
Uma matriz é uma estrutura de dados bidimensional que utiliza dois tipos de
índices, um para indicar a linha e outro para indicar a coluna. Ao criar uma
matriz, precisamos indicar quantas linhas e quantas colunas ela terá, bem
como o tipo de dado que ela armazenará. Em C, as matrizes são de alocação
estática e sequencial.

Algumas linguagens oferecem vetores e matrizes com alocação dinâmica, como, por
exemplo, a linguagem PHP. Cada vez que estivermos trabalhando com uma linguagem
diferente, precisamos entender os recursos que ela oferece e como manipular cada
um destes.

Filas
A fila é uma estrutura de dados de alocação dinâmica que permite armazenar
dados utilizando a regra FIFO. A sigla FIFO significa que o primeiro elemento
que entrará na fila será o primeiro a sair (em inglês, first in first out). Mas o
que isso quer dizer? Vamos pensar em uma fila de um banco. Sempre teremos
pessoas entrando na fila e essas pessoas entram no final dela, o que faz com
que ela aumente, no entanto, as pessoas, ao serem atendidas, estão saindo no
início da fila. A fila de um banco é uma fila do tipo FIFO.
Estrutura de Dados - II UNIDADE 2
8 Tipos abstratos de dados Tipos Abstratos de Dados 2 PARTE 3 125

Pilha
A pilha também é um tipo de estrutura de dados de alocação dinâmica, porém,
do tipo LIFO. A sigla LIFO significa que o último elemento que entrará na
fila será o primeiro a sair (em inglês, last in last out).
Vamos pensar em um aplicativo. A maioria deles tem muitas telas, ou seja,
as telas são empilhadas. Quando entramos na tela inicial de um aplicativo,
como, por exemplo, o WhatsApp, temos a tela de conversas. Agora vamos
pensar em abrir uma conversa e o que acontece? O app acaba de empilhar duas
telas, ou seja, a tela inicial, mais a tela da conversa selecionada. Quando você
pressiona o botão de sair ou fechar, a última tela aberta é a tela que será fechada.

Lista
A lista é uma estrutura linear na qual a posição atual aponta para o próximo
elemento da lista e sempre o último elemento apontará para nulo, indicando
que não há mais nenhum elemento na lista.
Há dois tipos de lista: a linear encadeada e a duplamente encadeada. Na
primeira, só é possível percorrer do início ao fim, enquanto na segunda é
possível percorrer para frente e para trás.

Árvores
As árvores são um pouco mais complexas do que filas, pilhas e listas. Esse tipo
de estrutura tem um conceito diferente das demais estruturas, isso porque os
dados serão dispostos em árvore de forma hierárquica, tendo cada elemento
um ou mais elementos associados.
Para começar a entender árvore, vamos tentar imaginar alguns exemplos.
Imagine uma empresa e sua estrutura de funcionários e cargos dispostos em
um organograma. Um organograma é uma representação de uma árvore, em
que nós teremos, conforme a Figura 2.
126 ESTRUTURA DE DADOS
Tipos abstratos de dados 9

Figura 2. Organograma representando a estrutura de cargos em uma


empresa.

Agora vamos imaginar uma estrutura de pastas no computador, no qual


podemos ter diversas pastas, sendo que podemos ter mais de uma pasta dentro
de outra, sem contar os diversos tipos de arquivos que podem ter dentro de
cada uma destas: isso é uma árvore.
Pense que, em uma árvore, os dados não estão sequenciais como em uma
fila ou pilha, por exemplo. Você pode entrar em uma pasta e ter mais duas
lá, sendo que você pode ir para qualquer uma das duas, isso é mais ou menos
como chegar ao final de uma rua e poder ir para a direita ou para a esquerda.
Toda árvore tem, pelo menos, um elemento denominado raiz e seus ele-
mentos em um nível mais baixo, que são chamados de nodos ou nós. O último
elemento de uma árvore (quando não há mais nodos) é chamado de nó folha.

Grafos
Os grafos se baseiam em dois conjuntos de dados, um conjunto em que são
armazenados os vértices, outro conjunto de arcos e uma função que associa os
pares de vértices. Esses conjuntos servem, basicamente, para percorrer uma
árvore, conforme visto anteriormente. A árvore tem raiz e pode ter filhos e
mais filhos, ou seja, pode ser uma estrutura complexa para percorrer.
Vamos imaginar um exemplo prático para entender uma estrutura de grafo.
Pense o seguinte: você está em casa e precisa sair para ir até o centro de sua
cidade. Quantas rotas você pode escolher? Com certeza mais de uma, certo?
Estrutura de Dados - II UNIDADE 2
10 Tipos abstratos de dados Tipos Abstratos de Dados 2 PARTE 3 127

A sua casa seria considerada um ponto (vértice) A, enquanto o centro seria o


destino, o ponto (vértice) B. As possíveis rotas seriam os arcos na árvore pelos
quais o algoritmo de grafo percorreria.
Agora imagine que os aplicativos, como por exemplo Google Maps ou
Waze, fazem exatamente isso. Eles escolhem a melhor rota de um ponto A
até o B, levando em consideração o caminho que utilizará o menor tempo.

Pré e pós-condições
Para manipular estruturas de dados, criamos métodos e rotinas, as quais
necessitam de pré e pós-condições. Estas permitem que o desenvolvedor
indique o que o método ou a rotina devem realizar.

Pré-condição
A pré-condição é tudo, por exemplo, que vai anteceder a execução de algum
algoritmo. Indica o que deve ser verdadeiro quando a rotina ou o método forem
acionados, como por exemplo:

Para realizar a divisão de dois números, precisamos ter dois números, o valor e o
divisor, ou seja, a pré-condição é receber os dois números e o divisor não pode ser 0.
Vamos observar o trecho de código abaixo:

float dividirNumeros(float valor, float divisor){


//pré-condição: divisor não pode ser 0
return valor / divisor;
}

Para que essa função funcione como pré-condição, ela deve receber dois números,
sendo que o segundo não pode ser 0. Caso um deles não seja informado ao acionar
a função, não será possível executar seu comando.
Assim, para acionar a função acima, utiliza-se seu nome e entre parênteses devemos
informar o valor correspondente a valor e o valor correspondente a divisor:

resultado = dividirNumeros(10, 2);


128 ESTRUTURA DE DADOS Tipos abstratos de dados 11

Pós-condição
A pós-condição é tudo que vai acontecer após a execução de algum algoritmo,
como, por exemplo, após somar os dois números, a função será responsável
por retornar a soma deles.
Vamos observar o trecho de código abaixo:

float somarNumeros(float num1, float num2){


return num1 + num2;
}

No trecho de código acima, o comando return indica que a função retornará


ao resultado da soma de num1 e num2. Espera-se que o trecho de código abaixo
retorne ao valor 10 para a variável resultado:

resultado = somarNumeros(7,3);

Acesse o link ou código a seguir para verificar uma apre-


sentação sobre pré e pós-condições.

https://goo.gl/SkeTDt

Vamos imaginar que estamos em um caixa eletrônico. Nele, temos várias opções, sendo
que cada uma delas será executada por uma ou mais funções, como, por exemplo:
 função de sacar;
 função de depositar;
 função de transferir.
Estrutura de Dados - II UNIDADE 2
Tipos Abstratos de Dados 2 PARTE 3 129
12 Tipos abstratos de dados

Para que a função de sacar funcione, ela necessita de condições, tais como:

Pré-condições:
 a função necessita receber uma quantia para poder efetuar o saque da conta,
devendo ser um valor inteiro e positivo;
 a função necessita verificar se a conta tem no mínimo a quantia solicitada para
o saque.

Pós-condições:
 a função deve separar a quantia desejada para o cliente;
 a função deve emitir um comprovante eletrônico ou impresso para o cliente.

Referência

SILVA, R. L.; OLIVEIRA, A. M. Algoritmos em C. Juiz de Fora: Clube de Autores, 2014.

Leituras recomendadas
BACKES, A. R. Estrutura de dados descomplicada: em linguagem C. Rio de Janeiro:
Elsevier, 2016.
BARANAUSKAS, J. A. Pré-condições e pós-condições. [2010?]. Algoritmos e Estruturas
de Dados I. Disponível em: <http://dcm.ffclrp.usp.br/~augusto/teaching/aedi/AED-
-I-Pre-Pos-Condicoes.pdf>. Acesso em: 19 mar. 2018.
FARIAS, R. Filas – Queue. 2009. Disponível em: <http://www.cos.ufrj.br/~rfarias/cos121/
filas.html>. Acesso em: 19 mar. 2018.
FARIAS, R. Pilhas – Stack. 2009. Disponível em: <http://www.cos.ufrj.br/~rfarias/cos121/
pilhas.html>. Acesso em: 19 mar. 2018.
FEOFILOFF, P. O que é um grafo? 2017. Disponível em: <https://www.ime.usp.br/~pf/
algoritmos_em_grafos/aulas/grafos.html>. Acesso em: 19 mar. 2018.
LAUREANO, M. A. P. Estrutura de dados com algoritmos e C. Rio de Janeiro: Brasport, 2008.
PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 4

Listas

O conteúdo deste livro é


disponibilizado por SAGAH.
132 ESTRUTURA DE DADOS

Listas
Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

 Reconhecer um TAD do tipo lista.


 Descrever os elementos de uma lista.
 Compor listas estáticas.

Introdução
Relacionar itens em listas é uma atividade comum no dia a dia de mui-
tas pessoas, seja para auxiliá-las em diversas atividades, como comprar
presentes de natal, construir uma relação de tarefas a serem executadas
ou até para definir os presentes de casamento. Na estrutura de dados,
as listas apresentam formas adequadas para automatizar processos do
mundo real, de acordo com a necessidade ou o objetivo da situação,
sem deixar de atender às características que definem os requisitos de
sua manipulação.
Neste capítulo, você estudará sobre o tipo abstrato de dados (TAD)
do tipo lista, descreverá e construirá lista s estáticas.

Tipo abstrato de dados do tipo lista


Um TAD é um dado definido com base nos tipos primitivos especificados pelas
linguagens de programação, como int, float e char, entre outros. Com ele, é
possível criar estruturas compostas de elementos de diversos tipos que podem
ser tratadas de forma agrupada (CELES; CERQUEIRA; RANGEL, 2004).
Estrutura de Dados - II UNIDADE 2
2 Listas Listas PARTE 4 133

Na linguagem C, uma estrutura TAD pode ser criada por meio da instrução
struct.

Nesse exemplo, a estrutura Aluno é um TAD composto de três elementos


diferentes: nome, como uma cadeia de caracteres; nota, como um número real; e
turma, como um número inteiro. Desse modo, pode-se manipular os elementos
da estrutura de forma individual ou agrupada, conforme você verá a seguir:

Já uma lista é um conjunto de dados que estão relacionados em determi-


nada ordem linear. Cada item dela representa um nó da cadeia e pode conter
elementos de apenas um tipo de dados primitivo ou de um tipo composto,
como um TAD (EDELWEISS; GALANTE, 2009).

De modo geral, as listas são amplamente utilizadas em sistemas computacionais, nos


quais diversas atividades do mundo real podem ser representadas por elas, como os
itens de um carrinho de compras de um site e-commerce, a relação de alunos aprovados
no vestibular de determinada universidade etc.

Os elementos de uma lista estão dispostos em uma ordem sequencial, em


posições consecutivas, nas quais não pode haver qualquer elemento nulo.
Assim, elementos inseridos ou excluídos da lista causarão deslocamento dos
outros itens para reorganizá-la (MATTOS; LORENZI; CARVALHO, 2007).
Na Figura 1, você verá como é a inclusão e a exclusão de um elemento na lista.
134 ESTRUTURA DE DADOS

Listas 3

inclusão exclusão
i i

1 2 3 4 1 2 3 4 5
a e o u a e i o u

1 2 3 4 5 1 2 3 4
a e i o u a e o u

Figura 1. Inclusão e exclusão de item na lista.

Na Figura 1, a inclusão do elemento i, entre as posições 2 e 3, causa deslo-


camento à direita das posições 3 e 4, que passam a ser 4 e 5, respectivamente.
Já na exclusão, a sua retirada da posição 3 causa deslocamento à esquerda das
posições 4 e 5, que passam a ser 3 e 4, respectivamente.

Uma lista estática do tipo TAD é determinada por uma quantidade limitada de itens,
geralmente implementada por meio de um array de elementos de uma estrutura
abstrata. Apesar de receber e perder itens, seu tamanho máximo é definido na sua
criação, por isso, se caracteriza como estática.

Você conhecerá a seguir as vantagens, as desvantagens e a indicação de


listas estáticas (FORBELLONE, 2005).

 Vantagens: o acesso direto aos elementos do array por meio de seu


índice e o tempo constante a cada acesso direto, independentemente
da quantidade de itens da lista.
 Desvantagens: o custo de processamento de inserção/exclusão ao preci-
sar reposicionar os elementos da lista, e o tamanho máximo predefinido
no momento de sua criação.
 Indicação: listas estáticas são recomendadas para listas pequenas,
quando é necessário limitar seu tamanho máximo, como a escalação
de um time titular de futebol, e sempre que a inclusão e a exclusão
de itens puderem ser realizadas preferencialmente na última posição.
Estrutura de Dados - II UNIDADE 2
4 Listas Listas PARTE 4 135

Uma lista estática do tipo TAD pode ser composta de dois elementos. O
primeiro é conhecido como dado e define um array da estrutura, por exemplo,
dado[MAX] que contém o nome, a nota e a turma de Aluno. Já o segundo
elemento, nomeado de n, é um contador que armazena o total de itens da lista
em tempo de execução.

Você verá um exemplo de elementos TAD em uma lista estática na Figura 2.

1 2 3 4 5

Nome Paula Pedro Ana Maria João

Nota 9.1 8.9 8.7 9.3 9.8

Turma 1 2 1 3 3

Figura 2. Exemplo de elementos TAD em uma lista estática.

Uma vez que a estrutura da lista é definida e declarada como um array de


elementos do tipo TAD, é necessário implementar a sua interface de acesso,
que são as funções que permitem manipulá-la, como incluir e excluir itens,
verificar se está vazia ou cheia, imprimir os seus elementos etc.

Interface de uma lista estática


Uma característica importante da lista estática é a separação entre a sua
estrutura de dados e a implementação dos métodos que fazem a sua interface
de acesso. Isso significa que um programador pode usar os seus métodos
sem conhecer os detalhes de sua implementação (MATTOS; LORENZI;
CARVALHO, 2007).
Não há uma definição de quais são exatamente os métodos de acesso de
uma lista estática, porque eles podem ser definidos com base nas funcionali-
136 ESTRUTURA DE DADOS Listas 5

dades e necessidades da aplicação que vai utilizá-la, sendo as mais conhecidas


(CELES; CERQUEIRA; RANGEL, 2004):

 criar uma lista vazia;


 identificar se a lista está vazia;
 identificar se a lista está cheia;
 excluir um item da lista;
 acessar uma posição da lista;
 inserir um item em uma posição da lista;
 inserir um item no final da lista;
 alterar um item da lista;
 identificar o número de itens da lista;
 concatenar duas listas;
 imprimir os elementos da lista;
 dividir a lista em duas ou mais;
 classificar a lista;
 inverter a ordem dos itens da lista.

Uma lista estática é mais genérica que filas e pilhas, porque não existe uma definição
de ordem de entrada ou retirada de elementos. Isso significa que esses itens podem
ser inseridos e excluídos de qualquer posição, desde que ela seja sequencial e não
tenha elementos nulos (EDELWEISS; GALANTE, 2009).

Principais funções de acesso a listas estáticas

Criação de uma lista vazia

Uma lista pode ser criada/inicializada quando o seu contador for definido como
zero, sem elementos, estando vazia e pronta para receber seus primeiros itens.
O algoritmo a seguir apresenta o pseudocódigo dessa função.
Estrutura de Dados - II UNIDADE 2
6 Listas Listas PARTE 4 137

Identificação de uma lista vazia

Uma lista está vazia quando o seu contador de elementos for igual a zero. O
pseudocódigo que ilustra o algoritmo dessa função será mostrado a seguir.

Identificação de uma lista cheia

Verificar se a lista está cheia é uma das funções mais importantes, uma vez
que ela não pode permitir mais elementos que a quantidade máxima prevista.
Para identificar isso, compara-se o seu contador de itens com a constante que
define o número máximo de elementos, conforme é descrito neste algoritmo:

Identificação do número de itens da lista

O número de itens de uma lista equivale ao seu contador de elementos, que


é atualizado a cada inserção ou exclusão. O algoritmo a seguir apresenta o
pseudocódigo dessa função.
138 ESTRUTURA DE DADOS Listas 7

Inserção de item na lista

A inclusão de um item na lista deve seguir as seguintes regras:

 verificar se ela está cheia;


 abrir um espaço para inserir o novo item e reacomodar os elementos para
não deixar alguma posição vazia, exceto se for inclui-lo no final da lista;
 incrementar o seu contador de itens.

A função que insere um novo elemento na lista deve receber três parâme-
tros: a lista que irá recebê-lo, a posição em que ele será inserido e o valor que
deverá ser armazenado.

Exclusão de item de uma posição da lista

Assim como a inclusão de itens, a exclusão deve seguir alguns critérios:

 verificar se ela está vazia;


 fechar o espaço deixado pelo elemento excluído, reacomodando os
demais itens, exceto se for exclui-lo do final da lista;
 decrementar o seu contador de itens.
Estrutura de Dados - II UNIDADE 2
Listas PARTE 4 139
8 Listas

A função que exclui um elemento da lista deve receber dois parâmetros:


a lista que terá o item retirado e a sua posição.

Impressão dos elementos de uma lista

Para imprimir a relação de itens de uma lista, o algoritmo deve percorrer


todos os elementos do array, partindo do início até o seu contador de itens,
que indica o seu número total.

Construção de listas estáticas


Você conhecerá a implementação, em linguagem C, dos principais métodos
de acesso da lista estática baseada em um TAD, que foram ilustrados em
pseudocódigo na seção anterior. Para isso, foram criados três arquivos.

 lista.h: arquivo de cabeçalho que contém os protótipos das funções e


a definição da estrutura TAD da lista.
 lista.c: arquivo que contém a implementação das funções.
 hello.c: arquivo que contém o método main e declara uma lista TAD
para chamar os métodos de acesso.
140 ESTRUTURA DE DADOS Listas 9

A estrutura TAD que será apresentada corresponde aos dados de um aluno


e contém três atributos: nome, nota e turma. Ela será armazenada em um array
de cinco elementos, que equivale aos itens da lista utilizada.

Arquivo lista.h
Esse arquivo define o número máximo de elementos da lista, a estrutura TAD
do aluno, o array que vai armazenar os dados desses alunos em cada posição
e os protótipos das funções de acesso a ela.
Estrutura de Dados - II UNIDADE 2
10 Listas Listas PARTE 4 141

Arquivo lista.c
Esse arquivo contém a implementação das funções de acesso à lista. Ele requer
a inclusão do arquivo lista.h que, por sua vez, inclui os protótipos das funções,
bem como a sua estrutura de definição.
142 ESTRUTURA DE DADOS Listas 11

Arquivo hello.c
Esse arquivo contém o módulo principal do exemplo, porque nele é realizada
a declaração do array da estrutura TAD Aluno e as chamadas das respectivas
funções de acesso à lista. Para acessar os métodos da lista, bem como a sua
estrutura, é preciso realizar a inclusão do arquivo lista.c.
Já para testar a inclusão de elementos na lista, deve-se criar uma função,
chamada “instancia”, que irá preparar os dados de entrada, tendo como pa-
râmetros as informações do aluno: nome, nota e turma.
Estrutura de Dados - II UNIDADE 2
12 Listas Listas PARTE 4 143

Nesse exemplo, você acompanhará a criação de uma lista de cinco posições


que armazenam a estrutura Aluno e a realização de algumas operações por
meio dos seus métodos, como cria-la, inserir e remover elementos, verificar
se está cheia e vazia, mostrar a quantidade de itens e imprimir a relação
completa de seus alunos.
144 ESTRUTURA DE DADOS

Listas 13

O resultado da execução desse programa está ilustrado na Figura 3. Ini-


cialmente, a lista foi criada e verificou-se se ela estava vazia e cheia (linhas
16 a 23). Na sequência, três alunos foram adicionados: Pedro, Ana e Maria,
nessa mesma ordem, e a relação foi impressa (linhas 25 a 37).
Em seguida, o aluno Pedro foi removido da primeira posição; e a lista para
ilustrar a retirada, impressa (linhas 39 a 42). Paula foi adicionada na primeira
posição, Pedro na segunda e João na quinta; e a lista, impressa novamente
(linhas 44 a 58). Por fim, verificou-se se a lista estava cheia, e a sua quantidade
de elementos foi mostrada (linhas 60 a 64).
Estrutura de Dados - II UNIDADE 2
Listas PARTE 4 145
14 Listas

Figura 3. Resultado da execução do programa de exemplo.

CELES, W.; CERQUEIRA, R.; RANGEL, J. L. Introdução a estrutura de dados. São Paulo:
Campus, 2004.
EDELWEISS, N.; GALANTE, R. Estrutura de dados. Porto Alegre: Bookman, 2009. (Série
Livros Didáticos Informática UFRGS, v. 18).
FORBELLONE, A. L. Lógica de programação: a construção de algoritmos e estruturas
de dados. 3. ed. São Paulo: Pearson, 2005.
MATTOS, P.; LORENZI, F.; CARVALHO, T. Estruturas de dados. São Paulo: Thomson, 2007.
PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 5

Listas Sequenciais

O conteúdo deste livro é


disponibilizado por SAGAH.
148 ESTRUTURA DE DADOS

Listas sequenciais
Objetivos de aprendizagem
Ao final da leitura deste capítulo, você deverá apresentar os seguintes
aprendizados:

 Identificar o funcionamento de uma lista (inserção, remoção, atuali-


zação e consulta em qualquer ponto da lista).
 Reconhecer como funcionam as funções e os procedimentos de uma
lista (inserção, remoção, atualização e consulta).
 Aplicar o uso de listas.

Introdução
As listas sequenciais são estruturas que servem para armazenar elementos
de maneira relacionada e lógica, ficando estes dispostos um depois do
outro, por isso o nome sequencial dado a ela. Na literatura, encontramos as
listas sequenciais referenciadas também por listas lineares, listas estáticas
lineares ou listas estáticas sequenciais. A sua aplicação é mais adequada
para os casos em que o conjunto de dados é pequeno e bem definido
e para quando for possível fazer as operações de inserção e remoção de
elemento no final da lista.
Neste capítulo, você vai estudar o funcionamento de uma lista, reco-
nhecer como funcionam as funções e os procedimentos de uma lista, tais
como a inserção, a remoção, a atualização e a consulta de um elemento,
e também como aplicar as listas sequenciais.

O funcionamento de uma lista (inserção,


remoção, atualização e consulta em qualquer
ponto da lista)
Uma lista sequencial é um tipo de estrutura que serve para fazer o armazena-
mento de elementos de uma forma relacionada e lógica, de maneira que estes
estejam dispostos um depois do outro. Por conta disso, uma lista sequencial
Estrutura de Dados - II UNIDADE 2
2 Listas sequenciais Listas Sequenciais PARTE 5 149

ou linear pode ser chamada também de lista estática linear ou lista estática
sequencial (LAUREANO, 2008).
Quando se trabalha com uma estrutura do tipo lista, é possível saber o
seguinte sobre ela:

 qual é o seu primeiro elemento;


 que elemento vem depois de um determinado elemento;
 qual é o seu último elemento;
 quantos elementos existem na lista toda;
 como se faz para inserir um elemento na lista;
 como se faz para remover um elemento da lista.

Uma lista estática sequencial é mais adequada para os casos em que o con-
junto de elementos é pequeno, quando existe um tamanho bem definido para
a quantidade de elementos da lista, e para quando se deseja fazer a inserção
ou a remoção de elementos no final da lista.
A utilização de uma lista estática sequencial traz como vantagens básicas:

 a possibilidade de acesso direto, por meio de índices, a qualquer um


dos elementos da lista;
 um tempo de demora uniforme para efetivar o acesso a qualquer um
dos elementos, pois isso vai depender apenas do índice.

Em contrapartida, a utilização desse tipo de lista também traz algumas


desvantagens:

 movimentação, em alguns casos, de toda a lista para que um elemento


seja inserido ou removido;
 o tamanho máximo deve ser predefinido e não poderá ser redefinido
em tempo de execução da aplicação.

De acordo com os tipos de operações que são permitidas, e que podem


ser realizadas, as listas sequenciais podem ser classificadas em filas, pilhas
e deques (LORENZI; MATTOS; CARVALHO, 2007).
Uma fila é uma lista sequencial, em que o primeiro elemento a entrar
também é o primeiro elemento a sair. Essa característica, a principal da fila,
é conhecida pela expressão em inglês FIFO ( first in first out). Em uma fila, os
elementos são inseridos pela parte de trás e são removidos pela parte da frente.
150 ESTRUTURA DE DADOS
Listas sequenciais 3

É possível fazer a abstração de uma fila imaginando pessoas em uma fila de


banco, ou uma fila de formigas trabalhando e descarregando alimento, sendo
assim, fica claro que a remoção de um elemento é pela frente e a inserção é
feita pela parte de trás (Figura 1).

Figura 1. Exemplo de fila.


Fonte: Nemeroff (2017).

Uma pilha é uma lista sequencial, sendo que o primeiro elemento a entrar
será o último elemento a sair. Essa característica é conhecida também pela
expressão em inglês LIFO (last in first out). A pilha só tem uma entrada, que é
o topo, e é a partir dele que os elementos entram e saem da estrutura (Figura 2).
Para fazer a abstração de uma pilha, imagine uma pilha de pratos, ou uma pilha
de livros, ou ainda uma pilha de cartas de baralho. Fazer a inserção e a remoção
de um elemento pelo topo é uma atividade bem mais prática nessas pilhas.
Estrutura de Dados - II UNIDADE 2
Listas Sequenciais PARTE 5 151
4 Listas sequenciais

Figura 2. Exemplos de pilhas.


Fonte: Victoria Shapiro/Shutterstock.com, Galyna Motizova/Shutterstock.com.

Um deque é uma lista sequencial na qual os elementos podem sair ou entrar


pela parte da frente ou de trás. Por isso, essa estrutura é conhecida como
deque (do inglês double ended queue). O deque pode ser definido como uma
generalização da estrutura fila.
A lista sequencial deve conter elementos de um mesmo tipo de dados, os
quais estão dispostos em sequência lógica e também em sequência física. A
sua implementação é feita em forma de vetor, que pode estar ordenado ou
não e ter elementos repetidos ou não. A alocação da memória é estática e a
forma de armazenamento na memória é sequencial, ou seja, os elementos são
armazenados em endereços de memória vizinhos.
Dentro de uma lista sequencial, os elementos ficam dispostos de forma
consecutiva, sendo que nenhum deles pode ser nulo. Nesse sentido, quando
um novo elemento é inserido, ou quando um dos elementos existentes é remo-
vido da lista, isso causa um deslocamento dos demais itens, a fim de torná-la
organizada novamente, caso ela seja uma lista ordenada.
Algumas das operações que podem ser executadas com listas sequenciais
são:

 Criação da lista: a sua criação acontece quando se declara o vetor que


vai conter os seus elementos.
 Inicialização da lista: envolve a preparação da lista para que sejam
inseridos os elementos. Inicialmente, a lista possui 0 elementos.
 Inserção de elemento: se a lista estiver desordenada, consiste em in-
serir um elemento na primeira posição disponível do vetor e ajustar a
quantidade de elementos caso a lista esteja cheia.
152 ESTRUTURA DE DADOS Listas sequenciais 5

 Percorrer a lista: envolve mostrar os valores de todos os elementos da


lista em qualquer direção.
 Pesquisar na lista: consiste na busca sequencial, de elemento por ele-
mento, de um valor ao longo da lista. Consiste em procurar um valor
dentro da lista.
 Remoção de elemento: envolve o ajustamento da organização dos ele-
mentos da lista e também da quantidade. É importante lembrar que
um elemento só pode ser removido da lista se ela não estiver vazia e
se ele for encontrado.
 Concatenação de listas: é a união de duas listas em uma lista única.
 Partição de listas: consiste em repartir uma lista em duas ou mais listas.

Como funcionam as funções e


os procedimentos de uma lista
(inserção, remoção, atualização e consulta)
A criação de uma lista sequencial acontece quando é declarado o vetor que
vai conter os elementos da lista (Figura 3).

0 1 2 3 4

int n
Figura 3. Criação de uma lista sequencial.

Na Figura 3, o vetor da lista foi declarado com 5 elementos e a variável n


será responsável por armazenar a quantidade de elementos da lista em tempo
de execução.
A inicialização de uma lista consiste em prepará-la para que sejam inseri-
dos elementos. Nesse momento, a variável n vai conter 0, que é a quantidade
inicial de elementos da lista. É importante observar que, quando uma lista
Estrutura de Dados - II UNIDADE 2
6 Listas sequenciais Listas Sequenciais PARTE 5 153

é sequencial, a variável n poderá ser entendida também como a variável que


guarda a posição em que um elemento novo deverá ser inserido (Figura 4)
(DEITEL; DEITEL, 2011).

0 1 2 3 4

a b c d e

int = 5
Figura 4. Inicialização de uma lista sequencial.

Na Figura 4, é possível observar que, caso um elemento contendo a letra


f precise ser inserido na lista, ele será colocado na posição 5, que também
corresponde à quantidade de elementos da lista.
A inserção de uma lista sequencial levará em conta que ela pode ou não
estar ordenada, e pode ou não conter elementos repetidos. Nesse sentido, um
elemento novo será inserido na posição equivalente ao valor da variável n e
deverá ser feito um ajuste na quantidade de dados da lista, desde que ela já
não esteja cheia.
Para que um elemento novo seja inserido na lista, é preciso conhecer o
vetor que a representa, o valor que precisa ser inserido, a quantidade atual de
elementos da lista e qual o tamanho máximo da lista (Figura 5).

0 1 2 3 4

Figura 5. Inserção de elemento em uma lista sequencial.


154 ESTRUTURA DE DADOS Listas sequenciais 7

A função de inserção será semelhante ao português estruturado:

Na função main, o usuário deverá informar um valor, o qual será arma-


zenado na variável valor, e será feita uma chamada para a função inserir,
passando os quatro parâmetros necessários.
A consulta em uma lista sequencial é uma operação que faz uma busca
sequencial, elemento por elemento, a fim de encontrar um determinado valor,
retornando à posição em que ele foi encontrado. Para que essa operação fun-
cione, é necessário conhecer o vetor da lista, o valor que deve ser procurado
e a quantidade atual de elementos da lista.
A função de consulta deve ser semelhante a esta:

Na função main, o usuário deverá informar um valor para ser consultado


na lista, o qual será armazenado na variável valor, e será feita uma chamada
para a função consultar, passando os três parâmetros necessários.
A remoção de um determinado elemento de uma lista sequencial, que pode
ou não estar ordenada, é uma operação que envolve o ajustamento do vetor
e da sua quantidade, lembrando que a remoção só poderá ser feita se a lista
não estiver vazia e se o elemento for encontrado (DEITEL; DEITEL, 2011).
Para implementar essa função, é preciso conhecer o vetor da lista, o valor a
ser removido da lista e a quantidade de elementos existentes na lista.
Estrutura de Dados - II UNIDADE 2
8 Listas sequenciais Listas Sequenciais PARTE 5 155

A função de remoção deve ser semelhante a esta:

Na função main, o usuário deverá informar um valor a ser removido e será


feita a chamada da função remover, passando os três parâmetros necessários.
A atualização de um elemento da lista envolve uma operação semelhante
à consulta, pois é necessário varrer a lista para encontrar o elemento a ser
alterado. Para que essa operação funcione, é necessário conhecer o vetor da
lista, o valor que deve ser procurado, o novo valor do elemento e a quantidade
de elementos atual da lista.
A função de atualização deve ser semelhante a esta:

Na função main, o usuário deverá informar um valor para ser consultado


na lista e também um valor novo para esse elemento. Deverá ser feita uma
chamada para a função atualizar, passando os quatro parâmetros necessários.

O uso de listas
As listas sequenciais são utilizadas, preferencialmente, quando é necessário
manipular listas pequenas, quando se pode limitar o seu tamanho e quando
a inserção e a remoção de um elemento puderem ser realizadas utilizando a
última posição.
156 ESTRUTURA DE DADOS

Listas sequenciais 9

Nesse sentido, aplicações que manipulem listas, como a escalação de um


time de futebol, os alunos de uma determinada disciplina, os funcionários de
um setor, entre tantas outras que se encaixem nesses critérios, consistem em
boas aplicações para listas sequenciais.

As listas são muito utilizadas em sistemas computacionais, pois diversas atividades


do mundo real podem ser abstraídas e representadas por elas. Entre as utilizações
possíveis para as listas, estão os itens de uma lista de compras, a relação de candidatos
aprovados no vestibular de determinada faculdade, a listagem de funcionários de um
setor, a relação de jogadores escalados para um time, a relação de nomes de uma
lista telefônica, entre outras.

Para fazer a inserção de um elemento em uma lista, pode-se utilizar um


código em linguagem C:
Estrutura de Dados - II UNIDADE 2
10 Listas sequenciais Listas Sequenciais PARTE 5 157

Entre as linhas 10 e 16 do código acima, foi transcrito, para a linguagem de


programação C, o português estruturado apresentado anteriormente. É feito
um teste se a tentativa de inserção está ocorrendo em uma posição acima do
tamanho da lista e, se não estiver, insere-se o valor na posição liberada da
lista, que no caso é a 0, pois o elemento é o primeiro a ser inserido.
A função main solicita a digitação de um caractere pelo usuário, faz a cha-
mada para a função de inserção e depois apresenta os elementos da lista na tela.
A tela de execução do código acima deve ser semelhante à apresentada
na Figura 6.

Figura 6. Função de inserção de elemento em lista.

Se a intenção for elaborar uma função para fazer a consulta de um valor


na lista, o código do programa deverá se parecer com o seguinte:
Listas sequenciais 11
158 ESTRUTURA DE DADOS

Nas linhas 10 a 18 do código anterior, utiliza-se um laço for para verificar,


elemento a elemento, se o seu valor coincide com o valor informado pelo usu-
ário para servir de critério para a busca. Caso o valor seja igual ao que consta
naquela posição da lista, será exibida uma mensagem na tela com a posição
em que o valor foi encontrado. Caso contrário, será exibida uma mensagem
informando que o valor não consta na lista.
A função main solicita a digitação de um caractere pelo usuário, para que
ele seja procurado na lista, faz a chamada para a função de consulta e depois
apresenta os elementos da lista na tela.
A tela de execução do código acima deve ser semelhante à apresentada
na Figura 7.
Estrutura de Dados - II UNIDADE 2
Listas Sequenciais PARTE 5 159
12 Listas sequenciais

Figura 7. Função de consulta de elemento em lista.

Para excluir um elemento da lista, deve-se utilizar um código de programa


semelhante ao apresentado a seguir:
160 ESTRUTURA DE DADOS
Listas sequenciais 13

Nas linhas 10 a 21 do código acima, utiliza-se um laço for para verificar,


elemento a elemento, se o seu valor coincide com o valor informado pelo
usuário para servir de critério na busca e na remoção. Caso o valor seja igual
ao que consta naquela posição da lista, todos os elementos da lista serão
deslocados, a fim de deixar livre o último elemento, e o tamanho da lista é
atualizado. Caso contrário, será exibida uma mensagem informando que o
valor não consta na lista.
A função main solicita a digitação de um caractere pelo usuário para que
ele seja removido da lista, faz a chamada para a função de remoção e depois
apresenta os elementos da lista na tela (Figura 8).

Figura 8. Função de remoção de elemento em lista.

Por fim, para fazer a atualização de um elemento da lista, o código deverá


se assemelhar ao seguinte:
14 Listas sequenciais Estrutura de Dados - II UNIDADE 2
Listas Sequenciais PARTE 5 161

Nas linhas 10 a 20 do código anterior, utiliza-se um laço for para verificar,


elemento a elemento, se o seu valor coincide com o valor informado pelo
usuário para servir de critério para a atualização. Caso o valor seja igual ao
que consta naquela posição da lista, o valor do elemento será alterado para o
novo valor, o qual foi informado pelo usuário. Caso contrário, será exibida
uma mensagem informando que o valor não consta na lista.
162 ESTRUTURA DE DADOS Listas sequenciais 15

A função main solicita a digitação de dois caracteres pelo usuário, sendo


que o primeiro será encontrado na lista e o segundo será o novo valor daquele
elemento, faz a chamada para a função de atualização e depois apresenta os
elementos da lista na tela (Figura 9).

Figura 9. Função de atualização de elemento em lista.

DEITEL, P.; DEITEL, H. C: como programar. 6. ed. São Paulo: Pearson Education, 2011.
818 p.
LAUREANO, M. Estrutura de dados com algoritmos e C. São Paulo: Brasport, 2008. 182 p.
LORENZI, F.; MATTOS, P.; CARVALHO, T. Estruturas de dados. São Paulo: Cengage Le-
arning, 2007. 200 p.
NEMEROFF, N. 32ee0c45cd10702651560f31136dcdec.jpg. 12 mar. 2017. Altura: 601 pixels.
Largura: 650 pixels. 51 KB. Formato JPEG. Pngtree. Disponível em: <https://pngtree.
com/freepng/line-up-people_3030246.html>. Acesso em: 2 abr. 2018.

PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 6

Listas Encadeadas

O conteúdo deste livro é


disponibilizado por SAGAH.
164 ESTRUTURA DE DADOS

Listas encadeadas
Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

 Identificar formas de armazenamento em uma lista.


 Reconhecer o encadeamento simples em uma lista.
 Comparar lista encadeada com lista estática.

Introdução
Na estrutura de dados, as listas são, geralmente, utilizadas para relacionar
itens que precisam ser exibidos ou manipulados por meio de estrutu-
ras estáticas ou dinâmicas. Diversas são as atividades que podem ser
realizadas com listas e cada uma delas requer um tipo adequado, de
acordo com os objetivos e funcionalidades da aplicação. Ao conhecer
essas estruturas, um profissional de tecnologia da informação (TI) será
capaz de identificar o uso correto de cada tipo de lista, bem como poderá
apresentar soluções confiáveis e otimizadas para o desenvolvimento de
sistemas.
Neste capítulo, você estudará sobre formas de armazenamento em
lista, listas com encadeamento simples e comparação entre listas enca-
deadas e estáticas.

Formas de armazenamento em uma lista


Uma lista pode ser entendida como uma relação de itens que contém elementos
de um tipo primitivo ou de um tipo abstrato de dados (TAD). Essa relação
deve ser contínua e não pode conter elementos nulos nem espaços vazios que
interrompam a sequência da lista (EDELWEISS; GALANTE, 2009).
Listas, de um modo geral, são largamente utilizadas em sistemas com-
putacionais, uma vez que representam diversas rotinas do mundo real e que
podem ser automatizadas, como a relação de produtos em promoção de uma
loja e a listagem de alunos adimplentes de uma academia.
Estrutura de Dados - II UNIDADE 2
2 Listas encadeadas Listas Encadeadas PARTE 6 165

Diferente de filas e pilhas que possuem restrição no modo de inclusão e


exclusão de itens, as listas são mais abrangentes e permitem adicionar e remover
itens em qualquer posição e em qualquer ordem da relação, oferecendo, assim,
grande utilidade em rotinas automatizadas (EDELWEISS; GALANTE, 2009).
Na estrutura de dados, as listas podem ser classificadas em duas categorias:
estáticas e dinâmicas, que apresentam diferentes particularidades e modos de
operação, conforme você verá na sequência deste capítulo.

Lista estática
Uma lista estática é uma relação de itens armazenados em uma estrutura de
tamanho fixo, como um array. Nessa estrutura, a quantidade de elementos é
reservada no momento de sua criação e o seu tamanho não pode ser redimen-
sionado em tempo de execução (DEITEL; DEITEL, 2011).
A alocação de memória de uma lista estática é sequencial, isto é, os itens
estão localizados em posições contínuas da memória, o que permite a busca
de elementos ser realizada diretamente em determinada posição, por meio
de seu índice.
No entanto, por mais que uma lista estática não ocupe todas as posições
definidas na sua criação, os espaços de memória reservados por ela não po-
derão ser ocupados por outra aplicação. Dessa forma, o programa não utiliza
os recursos de memória de maneira eficiente, pois pode reservar mais que o
necessário (MATTOS; LORENZI; CARVALHO, 2007).
A Figura 1 apresenta uma lista que reserva 10 posições na memória, mas
que ocupa apenas as quatro primeiras.

1 2 3 4 5 10

a b c d ...

Figura 1. Representação na memória de uma lista estática.


166 ESTRUTURA DE DADOS Listas encadeadas 3

A inclusão e a exclusão de itens no interior da lista podem ser custosas,


ou seja, podem demandar mais recursos de processamento e demorar signi-
ficativamente para concluir a tarefa em listas grandes, uma vez que todos os
elementos, a partir do respectivo item incluído/excluído, devem ser reposicio-
nados na lista (MATTOS; LORENZI; CARVALHO, 2007).
As vantagens de uma lista estática são (FORBELLONE, 2005):

 agilidade nas consultas — acesso direto aos elementos por meio dos
índices do array;
 tempo de acesso constante — a velocidade das pesquisas não reduz
com o crescimento da lista.

As desvantagens de uma lista estática são (FORBELLONE, 2005):

 array de tamanho fixo — a lista não pode aumentar nem diminuir em


tempo de execução;
 custo de inclusão/exclusão de itens — o custo computacional é alto para
realocar os itens quando algum elemento é incluído ou excluído da lista.

Lista dinâmica
Uma lista dinâmica realiza a alocação de memória em tempo de execução
para a acomodação de novos itens, isto é, reserva memória apenas quando
precisa aumentar a lista e, quando reduz, libera a memória ocupada. Assim,
o programa utiliza a memória de forma dinâmica, sem ocupar mais espaço
que o necessário (DEITEL; DEITEL, 2011).
Não existe um índice de acesso aos elementos de uma lista dinâmica. A
lista mantém o endereço da posição inicial, sendo necessário percorrer os
itens de forma sequencial para encontrar determinado elemento na relação.
A relação entre os elementos de uma lista dinâmica se dá pelo uso de
ponteiros de memória, ou seja, cada elemento possui um apontador para o
endereço de memória de um ou mais elementos da lista, fazendo ela ficar
ligada, sem ocupar posições contínuas na memória (CELES; CERQUEIRA;
RANGEL, 2004). Observe a representação da Figura 2.
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas PARTE 6 167
4 Listas encadeadas

Mapa da memória principal

a b

c d

e f

Lista: a -> b -> c -> d -> e -> f

Figura 2. Representação na memória de uma lista encadeada simples.

As vantagens de uma lista dinâmica são (FORBELLONE, 2005):

 crescimento e redução dinâmica — capacidade de crescer e reduzir


a lista em tempo de execução;
 baixo custo de inserção e exclusão — ajusta o apontamento de memória
em apenas dois elementos a cada modificação realizada (anterior e
próximo);
 alocação dinâmica de memória — proporciona otimização da me-
mória principal, usando apenas o espaço necessário para acomodar os
elementos da lista;
 alocação eficiente — a alocação de endereços de memória é geren-
ciada pelo sistema operacional por meio das funções da linguagem de
programação.

As desvantagens de uma lista dinâmica são (FORBELLONE, 2005):

 alto custo de pesquisa — não existe um índice de acesso direto, devendo


realizar busca sequencial;
 tempo crescente de busca — o tempo gasto para encontrar elementos
cresce de acordo com o tamanho da lista.
168 ESTRUTURA DE DADOS

Listas encadeadas 5

“Não liberar memória alocada dinamicamente quando ela não mais for necessária
pode fazer com que o sistema esgote prematuramente sua memória. Algumas vezes
isso é chamado um vazamento de memória” (DEITEL; DEITEL, 2010, p. 552).

Em estrutura de dados, as listas dinâmicas podem ser divididas em duas


categorias: listas com encadeamento simples e listas com encadeamento duplo.

Encadeamento simples

Uma lista dinâmica baseada no encadeamento simples, ou simplesmente


encadeada, é uma relação de itens organizados em sequência, cujos itens
armazenam, além das informações do elemento, o endereço do próximo item
da lista (CELES; CERQUEIRA; RANGEL, 2004).
Nesse tipo de encadeamento, a varredura da lista ocorre apenas em uma
direção, ou seja, da esquerda para a direita, sem a possibilidade de fazer o per-
curso de volta. O último item da lista aponta para um endereço nulo, indicando
que se encontra na última posição, conforme você pode observar na Figura 3.

d
a c
b e

Figura 3. Lista simplesmente encadeada.


Estrutura de Dados - II UNIDADE 2
6 Listas encadeadas Listas Encadeadas PARTE 6 169

Encadeamento duplo

Uma lista dinâmica que se baseia no encadeamento duplo, ou duplamente


encadeada, é uma sequência de itens que apontam para dois endereços, além
de armazenar o conteúdo do próprio elemento. Esses ponteiros correspondem
aos endereços dos itens anterior e próximo na lista (CELES; CERQUEIRA;
RANGEL, 2004).
Por conter ponteiros que apontam para os elementos anterior e posterior, a
varredura pode ocorrer em ambos os sentidos, isto é, tanto da esquerda para
a direita como da direita para a esquerda. Os endereços anterior ao primeiro
item e posterior ao último apontam para nulo, indicando que a lista inicia e
termina neles, como você pode observar na Figura 4.

d
a c
b e

Figura 4. Lista duplamente encadeada.

Encadeamento simples em uma lista


Na seção anterior, você viu que, em uma lista simplesmente encadeada, cada
elemento mantém um ponteiro para o próximo elemento da lista, o que faz a
alocação ser dinâmica, uma vez que um novo espaço na memória será reservado
apenas quando um elemento for inserido.
A estrutura de um elemento em uma lista encadeada é dividida em três
partes (Figura 5), conforme descrito a seguir (MATTOS; LORENZI; CAR-
VALHO, 2007).
170 ESTRUTURA DE DADOS Listas encadeadas 7

 &e1: representa o endereço do próprio elemento na memória.


 e1: significa o conteúdo do elemento, que pode ser apenas de um tipo
primitivo ou um TAD.
 &prox: indica o endereço do próximo elemento da lista.

&e1

e1

&prox

Figura 5. Estrutura de um elemento de uma lista encadeada.

O limite de elementos de uma lista dinâmica é determinado pela quantidade


de memória que estiver disponível no dispositivo ou na máquina virtual que
rodar o aplicativo. Para isso, a linguagem C fornece as funções malloc e free,
para alocar e liberar recursos de memória em tempo de execução.
A estrutura de uma lista simplesmente encadeada está ilustrada na Figura
6, na qual você pode visualizar que cada elemento aponta para o endereço do
próximo item da lista, até que o último elemento aponta para nulo.

&e1 &e2 &e3 &e4

e1 e2 e3 e4

&prox &prox &prox &prox

Figura 6. Ilustração de uma lista encadeada.


Estrutura de Dados - II UNIDADE 2
8 Listas encadeadas Listas Encadeadas PARTE 6 171

Na linguagem C, uma lista simplesmente encadeada contendo o nome, a


nota e a turma de um estudante pode ser declarada da seguinte forma:

Note, na linha 9, que o atributo *prox da estrutura Nodo é declarado como


uma estrutura de Nodo. Isso significa que esse atributo pode armazenar um
endereço da mesma estrutura, que será utilizado para apontar para o próximo
elemento da lista.
No entanto, antes de criar um novo elemento, é preciso realizar a alocação
de memória, que é feita a partir do tamanho base da estrutura em conjunto
com a instrução malloc. Após a alocação, deve-se fazer o apontamento, isto
é, dizer quem aponta para ele e para quem ele aponta. O exemplo a seguir
insere o novo elemento na primeira posição da lista.

Para inserir um elemento no final da lista, basta percorrê-la até a última


posição e realizar o apontamento do novo item que foi criado. Lembre-se que
o próximo do último elemento é NULL, pois ele não aponta para ninguém.
172 ESTRUTURA DE DADOS Listas encadeadas 9

A impressão da lista é realizada de forma parecida com a inclusão no final,


ou seja, é preciso percorrer todos os elementos, desde o início até que o último
elemento aponte para NULL. O deslocamento na lista se dá pelo acesso ao
endereço do próximo item.

Por fim, deve-se liberar os recursos de memória alocados. Para isso, você
deve fazer uma varredura na lista e liberar cada elemento por meio da ins-
trução free.

Comparar lista estática e lista encadeada


Na estrutura de dados, listas estáticas apresentam comportamentos diferentes
de listas encadeadas. Para ambas as listas existem vantagens e desvantagens
na sua utilização, e o tipo de lista a ser escolhido vai depender das caracte-
rísticas da aplicação.
As principais operações, que diferenciam uma lista estática de uma lista
encadeada são a inserção e a exclusão, conforme apresentado a seguir.

Inserção de item
A inclusão de um elemento em uma lista estática pode fazer alguns elementos
da lista terem que ser reposicionados. Isso provoca deslocando dos elemen-
tos à direita do novo item para abrir espaço para a sua inserção, conforme
demonstrado na Figura 7.
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas PARTE 6 173
10 Listas encadeadas

1 2 3 4 5 6

a b c d e

1 2 3 4 5 6

a b x c d e

Figura 7. Inclusão de item da lista estática.

A inclusão de um elemento em uma lista dinâmica é realizada pelo en-


cerramento da conexão entre os itens que estavam ligados, fazendo o item
anterior apontar para o novo elemento e este apontar para o item posterior,
conforme apresentado na Figura 8.

d
a c
b e

d
a c
b e

Figura 8. Inclusão de item da lista dinâmica.


174 ESTRUTURA DE DADOS Listas encadeadas 11

Exclusão de item
Assim como na inclusão de um item em uma lista estática, a exclusão de um
elemento pode fazer alguns itens da lista terem que ser reposicionados. Assim,
ocorre o deslocando dos elementos à direita do item retirado para fechar o
espaço antes ocupado, conforme ilustrado na Figura 9.

1 2 3 4 5 6

a b c d e

1 2 3 4 5 6

a b c d e

Figura 9. Exclusão de item da lista estática.

A exclusão de um elemento em uma lista dinâmica encerra as ligações


anterior e posterior do item que foi excluído, religando seu antecessor ao seu
sucessor. Além disso, ocorre a liberação da memória que estava alocada para
o item que foi excluído, conforme demonstrado na Figura 10.

d
a c
b e

d
a
b e

Figura 10. Exclusão de item da lista dinâmica.


Estrutura de Dados - II UNIDADE 2
12 Listas encadeadas Listas Encadeadas PARTE 6 175

O Quadro 1 apresenta um resumo comparativo das diferenças entre as


listas estáticas e encadeadas, com base nas características e operações de
cada uma delas.

Quadro 1. Resumo comparativo.

Evento Lista estática Lista encadeada

Pesquisa A pesquisa é rápida, com acesso A pesquisa é mais lenta porque


pela direto ao item por meio do índice é sequencial, sempre partindo
posição do array. O tempo de busca é do primeiro elemento da lista.
constante, independentemente O tempo de busca considera
do tamanho da lista. a posição do elemento a ser
buscado e o tamanho da lista.

Pesquisa Essa pesquisa não usa o índice O desempenho é semelhante


por do array. Assim, precisa percorrer porque também precisa percorrer
conteúdo a lista sequencialmente até a lista sequencialmente, desde a
encontrar o item cujo conteúdo primeira posição até encontrar o
é igual ao pesquisado. item pesquisado.

Inserção É mais lenta porque precisa É mais rápida porque modifica


no meio reposicionar os itens à direita do os apontadores de dois itens
da lista elemento inserido. apenas, o anterior e o posterior
do item inserido.

Inserção É mais rápida porque acessa É um pouco mais custosa porque


no final diretamente a próxima posição precisa percorrer toda alista até
da lista livre por meio do índice do array. chegar à última posição antes
de inserir.

Exclusão É mais lenta porque precisa É mais rápida porque modifica


no meio reposicionar os itens à direita do os apontadores de dois itens
da lista elemento excluído. apenas, o anterior e o posterior
do item excluído.

Exclusão É rápida porque acessa É um pouco mais lenta porque


no final diretamente a última posição por precisa percorrer toda a lista até
da lista meio do índice do array. chegar à última posição antes de
excluir.

Tamanho Limitado e definido no mo- O limite é o tamanho da memória


da lista mento da declaração. Pode não livre no equipamento. Consome
ocupar todas as posições reser- apenas o necessário para acomo-
vadas e consumir memória sem dar os itens e aloca ou libera con-
necessidade. forme a lista cresce ou diminui.

Indicação Listas pequenas, com quantidade Listas grandes, sem limite defi-
de uso limitada de itens, cujas inserções/ nido de itens, que tendem a re-
exclusões são raras e ocorrem ceber mais inserções/exclusões
normalmente no final da lista. de elementos.
176 ESTRUTURA DE DADOS

Listas encadeadas 13

CELES, W.; CERQUEIRA, R.; RANGEL, J. L. Introdução a estrutura de dados. São Paulo:
Campus, 2004.
DEITEL, P. J.; DEITEL, H. M. C: como programar. 6. ed. Rio de Janeiro: Pearson, 2011.
EDELWEISS, N.; GALANTE, R. Estrutura de dados. Porto Alegre: Bookman, 2009. (Série
Livros Didáticos Informática UFRGS, v. 18).
FORBELLONE, A. L. Lógica de programação: a construção de algoritmos e estruturas
de dados. 3. ed. São Paulo: Pearson, 2005.
MATTOS, P.; LORENZI, F.; CARVALHO, T. Estruturas de dados. São Paulo: Thomson, 2007.

PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 7

Listas Encadeadas Simples

O conteúdo deste livro é


disponibilizado por SAGAH.
178 ESTRUTURA DE DADOS

Listas encadeadas simples


Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

„ Reconhecer uma lista encadeada simples.


„ Especificar operações de manipulação de uma lista encadeada simples.
„ Identificar operações de acesso a uma lista encadeada simples.

Introdução
As listas encadeadas simples são normalmente utilizadas para relacionar
itens que precisam ser exibidos ou manipulados por meio de estruturas
dinâmicas. Com isso, é possível implementar operações que permitem
redimensionar as listas de acordo com a quantidade de itens manipulados,
ocupando exatamente a memória necessária para alocar os elementos
que pertencem à lista. Conhecer a definição das listas encadeadas sim-
ples, bem como suas operações de manipulação e acesso, permite que
o profissional de TI (tecnologia da informação) identifique e aplique
soluções confiáveis e otimizadas para o desenvolvimento de sistemas.
Neste capítulo, você vai estudar sobre listas encadeadas simples e
suas operações de manipulação e acesso.

Lista encadeada simples


Uma lista encadeada simples, ou lista dinâmica simplesmente encadeada,
é uma relação de elementos ligados em sequência, em que cada elemento é
composto de uma estrutura que pode conter variáveis de diversos tipos de
dados. Nesse tipo de lista, os elementos são alocados e deslocados em tempo
de execução, fazendo com que a lista cresça ou diminua dinamicamente de
acordo com a necessidade da aplicação (EDELWEISS; GALANTE, 2009).
Estrutura de Dados - II UNIDADE 2
2 Listas encadeadas simples Listas Encadeadas Simples PARTE 7 179

A ligação entre os elementos da lista ocorre pelo encadeamento simples, isto


é, cada nó que armazena um elemento da estrutura guarda o endereço físico
do próximo elemento na memória, isso faz com que não seja preciso alocar
espaços contínuos de memória, como as listas estáticas, pois o encadeamento
é lógico e não físico (Figura 1) (CELES; CERQUEIRA; RANGEL, 2004).

Mapa da memória principal

a b

c d

e f

Lista: a -> b -> c -> d -> e -> f

Figura 1. Representação na memória de uma lista encadeada simples.

A forma que um elemento tem de acessar o endereço físico da memória do


próximo elemento da lista se dá por meio de ponteiros. Os ponteiros funcionam
como apontadores que fazem referência a determinadas posições de memória,
isto é, toda variável declarada, seja de um tipo primitivo ou composto, tem
um endereço referenciado na memória e esse endereço é usado para realizar
o encadeamento da lista.
A estrutura de um elemento em uma lista encadeada simples é dividida em
três partes (Figura 2) (MATTOS; LORENZI; CARVALHO, 2007).
180 ESTRUTURA DE DADOS
Listas encadeadas simples 3

&e1

e1

&prox
Figura 2. Estrutura de um elemento de uma lista encadeada.

„ &e1 representa o endereço do próprio elemento na memória;


„ e1 armazena o conteúdo do elemento, que pode ser apenas um tipo
primitivo ou um tipo composto que contém inúmeras variáveis de
diferentes tipos de dados;
„ &prox indica o endereço físico da memória do próximo elemento da lista.

O encadeamento simples define que os elementos armazenam o endereço


da memória do próximo elemento da lista. Isso significa que a lista só pode
ser percorrida em um único sentido, a partir do início até a última posição, a
qual aponta para nulo, ou seja, para nenhum outro elemento (EDELWEISS;
GALANTE, 2009).
A estrutura de uma lista simplesmente encadeada está ilustrada pela
Figura 3. Nesse exemplo, percebe-se que cada elemento aponta para o en-
dereço do próximo elemento da lista, até que o último dos elementos aponte
para nulo, finalizando assim a relação.

&e1 &e2 &e3 &e4

e1 e2 e3 e4

&prox &prox &prox &prox

Figura 3. Ilustração de uma lista encadeada.


Estrutura de Dados - II UNIDADE 2
4 Listas encadeadas simples Listas Encadeadas Simples PARTE 7 181

Diferente de filas e pilhas, que têm restrição no modo de incluir e excluir


itens, as listas encadeadas simples são mais abrangentes e permitem adicionar
e remover elementos em qualquer posição e em qualquer ordem da relação
(CELES; CERQUEIRA; RANGEL, 2004).
Uma lista encadeada, por ser dinâmica, realiza a alocação da memória
para armazenar um novo elemento apenas quando este for incluído e, em
contrapartida, libera a memória quando determinado elemento é excluído,
ocupando apenas o espaço suficiente na memória para o tamanho atual da
lista (EDELWEISS; GALANTE, 2009).
O limite de elementos de uma lista encadeada simples é determinado pela
quantidade de memória que estiver disponível no dispositivo ou na máquina
virtual que rodar o aplicativo. Para isso, algumas linguagens de programação
oferecem comandos específicos para alocar e liberar recursos de memória em
tempo de execução (MATTOS; LORENZI; CARVALHO, 2007).
Não existe um índice de acesso direto aos elementos de uma lista dinâmica.
A lista mantém o endereço da posição inicial, sendo necessário percorrer os
itens de forma sequencial para encontrar determinado elemento na relação.
Vantagens de uma lista dinâmica (FORBELLONE, 2005):

„ crescimento e redução dinâmica: capacidade de crescer e reduzir a


lista em tempo de execução, sendo recomendada para listas grandes
que podem ter várias operações de inclusão e exclusão de elementos
em diversas posições;
„ baixo custo de inserção e exclusão: ajusta o apontamento de memória
em apenas dois elementos a cada modificação realizada (anterior e
posterior);
„ alocação dinâmica de memória: proporciona otimização da memória
principal, usando apenas o espaço necessário para acomodar os ele-
mentos da lista;
„ alocação eficiente: a alocação de endereços de memória é gerenciada
pelo sistema operacional pelas funções da linguagem de programação.

Desvantagens de uma lista dinâmica (FORBELLONE, 2005):

„ alto custo de pesquisa: não existe um índice de acesso direto, devendo


realizar busca sequencial;
„ tempo crescente de busca: o tempo gasto para encontrar elementos
cresce de acordo com o tamanho da lista.
182 ESTRUTURA DE DADOS

Listas encadeadas simples 5

“Não liberar memória alocada dinamicamente quando ela não mais for necessária
pode fazer com que o sistema esgote prematuramente sua memória. Algumas vezes
isso é chamado um vazamento de memória” (DEITEL; DEITEL, 2010, p. 552).

Operações de manipulação de uma lista


encadeada simples
As operações de manipulação de uma lista encadeada simples permitem efe-
tuar as ações que modificam a lista, como incluir, excluir e alterar elementos.
Dessas operações, a inclusão e a exclusão podem ser realizadas em qualquer
posição da lista, com tratamentos diferenciados para cada caso.

Definir uma lista


Uma lista encadeada simples é uma relação de elementos ligados em sequência.
Esses elementos normalmente são formados por estruturas compostas por
diversas variáveis, como um registro, as quais compreendem um domínio de
aplicação. São exemplos de estruturas (EDELWEISS; GALANTE, 2009):

„ dados de cadastro de clientes: CPF, nome, data de nascimento, ende-


reço, etc.;
„ características de um produto: código de barras, descrição, categoria,
preço, etc.;
„ estoque de produtos: código de barras, quantidade em estoque, preço
de aquisição, data de aquisição, etc.;
„ itens de venda de uma nota fiscal: número da nota, data de emissão,
CPF ou CNPJ do cliente, relação de produtos vendidos, etc.

A definição da lista estabelece a declaração de sua estrutura, incluindo as


variáveis e os seus tipos de dados, bem como uma variável adicional como
um ponteiro do mesmo tipo da lista para realizar o encadeamento entre os
elementos:
Estrutura de Dados - II UNIDADE 2
6 Listas encadeadas simples Listas Encadeadas Simples PARTE 7 183

//Definição da estrutura Produto


estrutura Produto (
codigoBarras : texto
descricao : texto
categoria : número inteiro
preco : número real)
//Definição da estrutura da listaProduto
estrutura ListaProduto (
produto : Produto
estrutura [ponteiro] proximoElemento : ListaProduto)

Inicializar uma lista


É preciso inicializar a lista antes de inserir algum elemento. Essa atividade é
bastante simples e requer, apenas, que seja definida como nula a variável que
identifica o próximo elemento da lista:

listaProduto.proximo = nulo

Incluir elemento na lista


Antes inserir um novo elemento na lista é preciso alocar um espaço de memória
para ele e, em seguida, preenchê-lo com os dados do registro. A inclusão de
um elemento pode ser realizada em qualquer posição da lista, sem precisar
deslocar os demais elementos. Isso ocorre porque, em uma lista dinâmica,
são modificados apenas os apontamentos entre os elementos, mantendo-os
nas posições de memória em que foram alocados.
A inclusão em uma lista encadeada simples pode ser realizada de três
maneiras distintas: no início, no final ou em qualquer posição intermediária
da lista. Para isso, devem ser ajustados os apontamentos que indicam quem
são os próximos elementos, para que a lista permaneça ligada e linear:

//Alocação de memória e atribuição de valores ao novo registro


novoProduto = alocarMemoria(listaProduto)
listaProduto.novoProduto.codigoBarras= 98712545611701
listaProduto.novoProduto.descricao= “Bolo de cenoura”
listaProduto.novoProduto.categoria= 1
listaProduto.novoProduto.preço= 5,99
184 ESTRUTURA DE DADOS Listas encadeadas simples 7

Incluir no início da lista

Incluir um novo elemento no início da lista é uma tarefa simples. Para isso, é
preciso ajustar o apontamento inicial da lista, que vai indicá-lo como primeiro
elemento, definindo como seu próximo elemento aquele que ocupava essa
posição anteriormente (Figura 4).

d
c
a e
b

d
a c
b e

Figura 4. Inclusão de um elemento no início da lista.

novoProduto.proximo = listaProduto.proximo
listaProduto.proximo = novoProduto
Estrutura de Dados - II UNIDADE 2
8 Listas encadeadas simples Listas Encadeadas Simples PARTE 7 185

Incluir no final da lista

Incluir um elemento no final da lista também é uma tarefa simples. Basta


percorrer a lista até a última posição, fazer com que o último elemento aponte
para o novo e este para nulo, pois o último elemento deve, necessariamente,
apontar para nulo para indicar o final da lista (Figura 5).

d
c
a b e

x
d
a c
b e

Figura 5. Inclusão de um elemento no final da lista.

enquanto listaProduto.proximo diferente nulo


ultimo= listaProduto.proximo
fim enquanto
ultimo.proximo= novoProduto

Incluir no meio da lista

Para incluir um elemento em uma posição intermediária da lista, é preciso fazer


uma varredura até a posição desejada e alterar os apontamentos, fazendo com
que o elemento anterior aponte para o novo e este para o elemento próximo
elemento (Figura 6).
186 ESTRUTURA DE DADOS

Listas encadeadas simples 9

d
a c
b e

d
a c
b e

Figura 6. Inclusão de um elemento no meio da lista.

enquanto listaProduto.proximo diferente nulo


se posição igual a posição desejada
temp= listaProduto.proximo
listaProduto.proximo= novoProduto
novoProduto.proximo= temp
fim se
fim enquanto

Excluir elemento da lista


Assim como a inclusão, a exclusão pode ser realizada em qualquer elemento
da lista. Para isso, é preciso encerrar as ligações anteriores e posteriores do
elemento que foi excluído, religando seu antecessor ao seu sucessor, mantendo
a lista ligada e linear.
Além disso, deve ocorrer a liberação da memória que estava alocada para o
item que foi excluído, fazendo com que a lista armazene apenas a quantidade
de memória necessária para o seu tamanho atual. Como exemplo, a Figura 7
apresenta a exclusão de um elemento posicionado no meio da lista.
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas Simples PARTE 7 187
10 Listas encadeadas simples

d
a c
b e

d
a
b e

Figura 7. Exclusão de item da lista dinâmica.

Excluir no início da lista

Excluir um elemento do início da lista é uma atividade muito simples. Para


isso, basta fazer com que a lista inicie pelo elemento que era sucessor do
elemento que foi excluído, bem como liberar a memória desse elemento que
deixou de pertencer à lista.

primeiro= listaProduto.proximo
listaProduto.proximo= primeiro.proximo
liberarMemoria(primeiro)

Excluir no final da lista

Para excluir um elemento do final, é preciso fazer uma varredura na lista até
chegar à última posição, definir o apontamento do penúltimo elemento como
nulo e liberar a memória do elemento que ocupava a última posição.

anterior= listaProduto
atual= listaProduto.proximo
enquanto atual.proximo diferente nulo
anterior= atual
atual= atual.proximo
188 ESTRUTURA DE DADOS
Listas encadeadas simples 11

fim enquanto
anterior.proximo= nulo
liberarMemoria(atual)

Excluir no meio da lista

Para excluir um elemento que ocupa uma posição intermediária, é necessário


percorrer a lista até encontrar o elemento desejado, identificando seu anterior
e sucessor. Na sequência, basta fazer o anterior apontar para o sucessor, bem
como liberar a memória que estava alocada para o elemento excluído.

anterior= listaProduto
atual= lisProduto.proximo
enquanto atual.proximo diferente nulo
se atual.proximo igual a valor
anterior.proximo= atual.proximo
liberarMemoria(atual)
sair
fim se
anterior= atual
atual= atual.proximo
fim enquanto

Excluir toda a lista

Para excluir uma lista encadeada inteira, é preciso percorrer todos os elementos,
a partir do início, e liberar a alocação de memória de cada elemento, bem como
indicar que seu próximo elemento aponta para nulo para evitar o apontamento
de alguma posição desatualizada na memória.

atual= listaProduto
enquanto atual.proximo diferente nulo
proximo= atual.proximo
atual.proximo= nulo
liberarMemoria(atual)
fim enquanto
Estrutura de Dados - II UNIDADE 2
12 Listas encadeadas simples Listas Encadeadas Simples PARTE 7 189

Operações de acesso a uma lista encadeada


simples
As operações de acesso a uma lista encadeada simples realizam as ações de
leitura, pesquisa e impressão, sem efetuar qualquer modificação. São consi-
deradas ações de apoio à manipulação de dados, pois atuam sobre os dados
já inseridos na lista.
Podem ser criadas diversas operações de acesso a uma lista, sendo que as
principais são: verificar se a lista está vazia, identificar o primeiro e o último
elementos, pesquisar um elemento qualquer por determinada informação e
imprimir a relação completa de elementos da lista.

Verificar se a lista está vazia

Uma lista encadeada está vazia se ela aponta para nulo, isto é, se ela não
aponta para nenhum elemento.

se (listaProduto.proximo igual a nulo) então


retornar positivo
senão
retornar negativo
fim se

Acessar o primeiro elemento da lista

Para acessar o primeiro elemento da lista, basta pegar o próximo elemento


do endereço da lista, já que esse endereço aponta para o primeiro elemento.

primeiro= listaProduto.proximo
imprime primeiro

Acessar o último elemento da lista

Não é possível acessar diretamente o último elemento da lista, uma vez que
uma lista encadeada simples não permite acesso direto aos elementos. Dessa
forma, é preciso percorrer toda a lista a partir do primeiro elemento.
190 ESTRUTURA DE DADOS
Listas encadeadas simples 13

elemento= listaProduto.proximo
enquanto elemento diferente nulo
se elemento.proximo igual a nulo
imprime elemento
fim se
elemento= listaProduto.proximo
fim enquanto

Pesquisar elemento na lista

Sabendo que uma lista encadeada simples não permite acessar diretamente
os elementos, é preciso realizar uma varredura na lista a partir da primeira
posição. Dessa forma, compara-se cada elemento da lista com o dado pesqui-
sado, buscando localizar a informação desejada.

elemento= listaProduto.proximo
enquanto elemento diferente nulo
se elemento.proximo igual a informação desejada
imprime elemento
fim se
elemento= listaProduto.proximo
fim enquanto

Imprimir toda a lista

Para imprimir a relação completa de elementos de uma lista encadeada sim-


ples, é preciso percorrer a lista a partir da primeira posição até que o último
elemento aponte para nulo.

elemento= listaProduto.proximo
enquanto elemento diferente nulo
imprime elemento
elemento= listaProduto.proximo
fim enquanto
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas Simples PARTE 7 191
14 Listas encadeadas simples

CELES, W.; CERQUEIRA, R.; RANGEL, J. L. Introdução a estrutura de dados. São Paulo:
Campus, 2004.
DEITEL, P. J.; DEITEL, H. M. Como programar em C. 6. ed. São Paulo: Pearson, 2011.
EDELWEISS, N.; GALANTE, R. Estrutura de dados. Porto Alegre: Bookman, 2009. (Série
Livros Didáticos Informática UFRGS, v. 18).
FORBELLONE, A. L. Lógica de programação: a construção de algoritmos e estruturas
de dados. 3. ed. São Paulo: Prentice Hall, 2005.
MATTOS, P.; LORENZI, F.; CARVALHO, T. Estruturas de dados. São Paulo: Thomson, 2007.
PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 8

Listas Encadeadas Duplas

O conteúdo deste livro é


disponibilizado por SAGAH.
194 ESTRUTURA DE DADOS

Listas encadeadas duplas


Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

 Identificar o uso de uma lista encadeada dupla.


 Reconhecer a navegação em uma lista encadeada dupla para inserir,
remover, atualizar e consultar valores.
 Aplicar a implementação de listas encadeadas duplas.

Introdução
Uma lista encadeada dupla é um tipo de lista dinâmica em que os ele-
mentos têm dois apontamentos: um para o elemento anterior e outro para
o elemento posterior. Com o encadeamento duplo, é possível percorrer
uma lista em ambos os sentidos, isto é, da esquerda para a direita e vice-
-versa, proporcionando mais versatilidade na navegação dos elementos
da lista. As operações em uma lista com encadeamento duplo são as
mesmas das listas simplesmente encadeadas, com pequenas variações
nos apontamentos existentes.
Neste capítulo, você vai estudar sobre o uso, a navegação e as ope-
rações com listas encadeadas duplas.

Lista encadeada dupla


Assim como uma lista encadeada simples, uma lista encadeada dupla é uma
relação de elementos ligados como uma sequência de itens. No entanto, no
encadeamento duplo, os elementos têm dois apontamentos, isto é, um para o
elemento anterior e outro para o posterior (EDELWEISS; GALANTE, 2009).
O primeiro e o último elementos da lista têm apenas um apontamento para
outros elementos, sendo que o anterior do primeiro e o posterior ao último
apontam para NULL, indicando o início e o final da lista, respectivamente,
como ilustrado a Figura 1.
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas Duplas PARTE 8 195
2 Listas encadeadas duplas

a e1 p a e3 p a e3 p

Figura 1. Apresentação de uma lista encadeada dupla.

De acordo com Celes, Cerqueira e Rangel (2004), uma lista dinâmica com
encadeamento duplo apresenta as seguintes características:

 Define um ponteiro para o primeiro elemento e outro para o último


elemento da lista. Esses ponteiros servem como ponto de referência
da lista e permitirão que ela seja percorrida, tanto a partir do início,
quanto do final.
 Cada elemento da lista tem dois atributos, do tipo ponteiro da lista, que
apontam para os elementos anterior e posterior.
 O anterior ao primeiro elemento aponta para null, indicando que a lista
inicia a partir desse elemento.
 O posterior ao último elemento da lista aponta para null, indicando que
a lista termina nesse elemento.
 Os elementos da lista podem ser variáveis de um tipo de dado primitivo
ou estruturas compostas por outras variáveis, como registros.

Na linguagem C, a declaração de uma lista duplamente encadeada pode


ser implementada com duas estruturas. A primeira especifica os detalhes do
que será armazenado como um registro, isto é, os atributos que compõem esse
conjunto de dados; e a segunda define propriamente a lista, ou seja, os dados
que serão armazenados e os ponteiros que indicam os elementos anterior e
posterior (LORENZI; MATTOS; CARVALHO, 2007).
Pode-se, ainda, declarar uma terceira estrutura para armazenar a quantidade
de elementos da lista, bem como o endereço de memória do primeiro e do
último elemento da lista. Essa estrutura é chamada de Descritor por Edelweiss
e Galante (2009) e serve de apoio para manipular a lista nos dois sentidos,
como, por exemplo, imprimir os elementos de trás para frente.
196 ESTRUTURA DE DADOS
Listas encadeadas duplas 3

Para exemplificar a declaração de uma lista dinâmica com encadeamento


duplo, tomamos por base o cadastro de alunos de uma escola. Esse cadastro
é composto por três atributos: nome, nota e turma.

A estrutura declarada nada mais é que a definição de um conjunto capaz


de armazenar os dados dos alunos. Entretanto, para declarar a lista, é preciso
definir uma estrutura que armazene um dado de Aluno e dois ponteiros, os
quais serão utilizados para fazer a ligação dos elementos:

Nessa estrutura, a variável dado é do tipo Aluno, isto é, armazena os atri-


butos dos alunos, como nome, nota e turma. Além disso, define as variáveis
*ant e *prox, como ponteiros para a mesma estrutura, que visam a armazenar
o endereço do anterior e do próximo elemento da lista.
A estrutura Descritor contém três variáveis, sendo uma do tipo inteiro
que armazena a quantidade de elementos da lista e duas do tipo ponteiro de
Nodo, que armazenam os endereços de memória do primeiro e do último
elemento da lista.
Estrutura de Dados - II UNIDADE 2
4 Listas encadeadas duplas Listas Encadeadas Duplas PARTE 8 197

Por ser uma lista dinâmica, a alocação e a liberação de memória ocorrem


em tempo de execução. Assim, a lista ocupa apenas o espaço necessário para
acomodar os elementos atuais, tornando-se uma ótima opção para os casos
em que não se sabe exatamente o tamanho da lista.
Uma vez que as estruturas estejam definidas, é preciso declarar as variáveis
que serão usadas para montar a lista. Para isso, declaramos uma variável do
tipo Aluno, uma variável do tipo Descritor e uma variável que representa a
lista, do tipo Nodo.

É preciso alocar memória para cada elemento a ser incluído na lista.


Na linguagem C, a instrução malloc realiza essa alocação com base no tamanho
da estrutura Nodo que, além de armazenar os dados do Aluno, armazena os
endereços dos nodos anterior e posterior.

Navegação em uma lista encadeada dupla para


inserir, remover, atualizar e consultar valores

Navegar em uma lista


A navegação em uma lista encadeada dupla pode ser realizada de duas for-
mas. A primeira e mais usual é a varredura a partir de seu início, por meio
do endereço do primeiro elemento. Já a segunda maneira varre a lista de trás
para frente, partindo do endereço do último elemento, cujo endereço está
armazenado no Descritor (EDELWEISS; GALANTE, 2009).
Ambas as formas precisam de uma estrutura de repetição, a qual fará a
navegação na lista pelos ponteiros que endereçam para os elementos anterior
e posterior de cada item da lista, fazendo com que seja possível percorrê-la
em qualquer sentido, conforme ilustra a Figura 2.
198 ESTRUTURA DE DADOS
Listas encadeadas duplas 5

Aluno
nome
nota
turma

&ant &ant &ant &ant

e1 e2 e3 e4
&prox &prox &prox &prox

&e1 n = 4 &e4
Descritor

Figura 2. Navegação em uma lista duplamente encadeada.

Incluir elemento na lista


A inclusão de elementos em uma lista duplamente encadeada pode ser rea-
lizada de três formas: no início, em uma posição intermediária e no final da
lista. Em cada uma dessas opções é preciso reajustar os apontamentos, de
modo que os elementos se liguem aos anteriores e posteriores (EDELWEISS;
GALANTE, 2009).
Para incluir um elemento na lista, é necessário alocar memória para receber
os dados do registro que serão armazenados na estrutura. Na sequência, deve-
-se redirecionar o ponteiro ant do novo elemento para o elemento anterior e
o ponteiro prox para o próximo elemento, cuidando para que o anterior do
primeiro elemento e o posterior do último apontem para NULL, indicando o
início e o final da lista, respectivamente (Figura 3).
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas Duplas PARTE 8 199
6 Listas encadeadas duplas

a e1 p a e3 p a e3 p

a e4 p

a e1 p a e3 p a e3 p

Figura 3. Inclusão em uma lista duplamente encadeada.

Excluir elemento da lista


Assim como na inclusão, a exclusão de elementos de uma lista encadeada dupla
pode ser realizada de três formas: no início, em uma posição intermediária e
no final da lista. Em cada uma dessas opções, é necessário reajustar os apon-
tamentos, de modo que os elementos se liguem aos anteriores e posteriores
(CELES; CERQUEIRA; RANGEL, 2004).
Para excluir um elemento na lista, é preciso liberar a memória que estava
alocada para guardar os dados do registro, bem como cuidar para que o anterior
do primeiro elemento e o posterior do último apontem para NULL quando a
exclusão envolver o início ou o final da lista (Figura 4).
200 ESTRUTURA DE DADOS
Listas encadeadas duplas 7

a e4 p

a e1 p a e3 p a p

a e4 p

a e1 p a e3 p

Figura 4. Exclusão em uma lista duplamente encadeada.

Consultar e atualizar elementos da lista


A consulta e a atualização de elementos em uma lista duplamente encadeada
são realizadas a partir da navegação nos itens da lista. Isso é necessário porque
a lista não tem um índice que acesse diretamente seus elementos, exceto o
primeiro e o último (LORENZI; MATTOS; CARVALHO, 2007).
Como citado anteriormente, a navegação pode ser realizada por meio de
uma estrutura de repetição. Dessa forma, as comparações podem ser realizadas,
ao percorrer a lista, visando a encontrar um determinado elemento que pode
ser apenas apresentado na tela ou até mesmo modificado.
Essas operações não requerem modificação nos ponteiros que ligam os
elementos, uma vez que apenas efetuam leitura ou atualização do conteúdo
dos itens, isto é, dos dados. Com isso, permanece a mesma quantidade de
elementos e seus respectivos apontamentos.
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas Duplas PARTE 8 201
8 Listas encadeadas duplas

Implementação de listas encadeadas duplas


Nesta seção, vamos apresentar a implementação de uma lista duplamente
encadeada na linguagem C, tomando por base as estruturas apresentadas
anteriormente. Assim, serão demonstradas as principais operações, como
iniciar uma lista, verificar se uma lista está vazia, retornar o primeiro e o último
elementos, incluir e excluir elementos no início e no final de uma lista, excluir
uma lista inteira e imprimir a relação completa de elementos de uma lista.

Iniciar uma lista


É preciso iniciar uma lista antes de utilizá-la pela primeira vez. Nessa função,
inicializam-se as variáveis Ponteiros e a quantidade de elementos do Descritor.

Verificar se a lista está vazia


Uma lista dinâmica está vazia se ela aponta para NULL ou se a quantidade de
elementos do Descritor for igual a zero. Isso significa que nenhum elemento
foi inserido ou que todos já foram excluídos. A função que identifica se uma
lista está vazia está descrita a seguir.
202 ESTRUTURA DE DADOS Listas encadeadas duplas 9

Acessar o primeiro e o último elementos da lista


Para acessar o primeiro ou o último elemento da lista, devem-se usar os
ponteiros do Descritor, os quais têm apontamentos para esses elementos,
conforme apresentado a seguir.

Incluir elemento na lista


Nesta seção, vamos apresentar a inclusão no início e no final da lista. Para
isso, verificamos se a lista está vazia para identificar a forma correta de incluir,
pois a regra é diferente quando já existem elementos na lista. Além disso,
devem-se ajustar os apontamentos dos ponteiros do novo elemento na lista,
conforme apresentado anteriormente.
Estrutura de Dados - II UNIDADE 2
Listas Encadeadas Duplas PARTE 8 203
10 Listas encadeadas duplas

Excluir elemento da lista


Assim como na inclusão, vamos apresentar as funções que excluem no início
e no final da lista. Para isso, deve-se diminuir a quantidade de elementos do
Descritor, bem como liberar a memória do elemento excluído sem deixar de
ajustar os apontamentos.
204 ESTRUTURA DE DADOS Listas encadeadas duplas 11

Excluir toda a lista


Para excluir toda a lista, é preciso realizar a navegação desde o início e liberar
a memória de cada elemento, diminuindo o contador do Descritor.
Estrutura de Dados - II UNIDADE 2
12 Listas encadeadas duplas Listas Encadeadas Duplas PARTE 8 205

Imprimir toda a lista


Há duas formas de imprimir toda a relação de elementos de uma lista dinâmica
com duplo encadeamento. A primeira é percorrê-la da esquerda para a direita
ou do início até o final, e a segunda é da direita para a esquerda ou do final
até o início.
A função imprimir pode ser personalizada para filtrar dados e apresentar
apenas determinados registros. Para isso, uma estrutura condicional precisa
ser implementada para verificar se os registros pesquisados atendem aos cri-
térios especificados. A condição de parada do laço de repetição se dá quando
o ponteiro do final ou do início da lista aponta para NULL.
206 ESTRUTURA DE DADOS

Listas encadeadas duplas 13

CELES, W.; CERQUEIRA, R.; RANGEL, J. L. Introdução a estrutura de dados: com técnicas
de programação em C. Rio de Janeiro: Campus, 2004. 294 p.
EDELWEISS, N.; GALANTE, R. Estrutura de dados. Porto Alegre: Bookman, 2009. 262 p.
(Série Livros Didáticos Informática UFRGS, 18).
LORENZI, F.; MATTOS, P.; CARVALHO, T. Estruturas de dados. São Paulo: Cengage Le-
arning, 2007. 200 p.

Leitura recomendada
FORBELLONE, A. L. V.; EBERSPÁCHER, H. F. Lógica de programação: a construção de
algoritmos e estruturas de dados. 3 ed. São Paulo, Pearson, 2005. 232 p.

PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
unidade

2
Parte 9

Lista Dinâmica

O conteúdo deste livro é


disponibilizado por SAGAH.
208 ESTRUTURA DE DADOS

Lista dinâmica
Objetivos de aprendizagem
Ao final deste texto, você deve apresentar os seguintes aprendizados:

 Definir uma lista dinâmica.


 Construir funções de manipulação de uma lista dinâmica.
 Desenvolver funções de acesso a uma lista dinâmica.

Introdução
As listas dinâmicas ou encadeadas são normalmente utilizadas para
relacionar itens que precisam ser exibidos ou manipulados em tempo
de execução. Com isso, é possível implementar métodos que permitem
redimensionar as listas conforme os itens são inseridos ou removidos,
ocupando exatamente a memória necessária para alocar os elementos
que pertencem à lista. Conhecer a implementação de listas dinâmicas
e seus métodos de acesso e manipulação permite que o profissional de
TI (tecnologia da informação) identifique e aplique soluções robustas e
otimizadas para o desenvolvimento de sistemas.
Neste capítulo, você vai estudar sobre listas dinâmicas e suas opera-
ções de manipulação e acesso com a linguagem C.

Lista dinâmica
Lista dinâmica, ou lista encadeada simples, é uma relação de elementos ligados,
formando uma sequência de itens na qual cada elemento se liga ao elemento
posterior. Os elementos dessa relação são formados por uma estrutura que
pode conter variáveis de vários tipos de dados (Figura 1) (EDELWEISS;
GALANTE, 2009).
Estrutura de Dados - II UNIDADE 2
Lista Dinâmica PARTE 9 209
2 Lista dinâmica

e1 e2 e3 e4

Figura 1. Apresentação de uma lista dinâmica.

De acordo com Celes, Cerqueira e Rangel (2004), uma lista dinâmica


apresenta as seguintes características:

 Define um ponteiro para o início da lista. Esse ponteiro serve como


ponto de referência da lista, apontando para o primeiro elemento, quando
houver, ou NULL se a lista estiver vazia.
 Cada elemento da lista tem um atributo do tipo ponteiro da lista, o qual
aponta para o próximo elemento.
 O último elemento da lista não aponta para NULL, isto é, para nenhum
outro elemento, caracterizando o final da lista.
 Os elementos da lista podem ser variáveis de tipo primitivo ou estruturas
compostas por outras variáveis, como registros.

Na linguagem C, a declaração de uma lista dinâmica pode ser implementada


por meio de duas estruturas. A primeira especifica os detalhes do que será
armazenado como um registro, isto é, os atributos que compõem esse conjunto
de dados; e a segunda define propriamente a lista (LORENZI; MATTOS;
CARVALHO, 2007).
Para exemplificar a declaração de uma lista dinâmica, tomaremos por base
o cadastro de produtos de determinada loja. Esse cadastro será composto por
quatro atributos: código de barras, descrição do produto, categoria e preço.
210 ESTRUTURA DE DADOS
Lista dinâmica 3

A estrutura declarada nada mais é que a definição de um conjunto capaz de


armazenar os dados dos produtos. No entanto, para declarar a lista, é preciso
definir uma estrutura que armazene um dado de produto e um ponteiro que
será utilizado para fazer a ligação dos elementos.

Nessa estrutura, a variável dado é do tipo Produto, isto é, armazena os


atributos de produto, como código de barras, descrição e outros. Além disso,
define a variável *prox, que é um ponteiro para a mesma estrutura, o qual
visa a armazenar o endereço do próximo elemento da lista, conforme ilustrado
na Figura 2.

Produto
codigoBarras
descricao
categoria
preco

e1 e2 e3 e4
&prox &prox &prox &prox

Figura 2. Ilustração de uma lista encadeada.

Por ser uma lista dinâmica, a alocação e a desalocação de memória ocorrem


em tempo de execução. Assim, a lista ocupa apenas o espaço necessário para
acomodar os elementos atuais, tornando-se uma ótima opção para os casos
em que não se sabe exatamente o tamanho da lista.
Estrutura de Dados - II UNIDADE 2
4 Lista dinâmica Lista Dinâmica PARTE 9 211

Uma vez que as estruturas estejam definidas, é preciso declarar as variáveis


que serão usadas para montar a lista. Para isso, vamos declarar uma variável
do tipo Produto e uma variável que representa a lista, do tipo Nodo.

É preciso alocar memória para cada elemento a ser incluído na lista. Na


linguagem C, a instrução malloc realiza essa alocação com base no tamanho
da estrutura Nodo que, além de armazenar os dados do Produto, armazena o
endereço do próximo Nodo.

Construir funções de manipulação


de uma lista dinâmica
As operações de manipulação de uma lista dinâmica efetuam as ações que
modificam a lista, como incluir, excluir e alterar elementos. As operações de
inclusão e exclusão podem ser realizadas em qualquer posição da lista, com
tratamentos diferenciados para cada caso. Veja na sequência deste capítulo
as principais operações de manipulação de listas dinâmicas.

Inicializar uma lista


Antes de inserir qualquer elemento em uma lista dinâmica, é necessário
inicializá-la. Para isso, basta definir como NULL a variável que identifica o
próximo elemento da lista.
212 ESTRUTURA DE DADOS
Lista dinâmica 5

Incluir elemento no início da lista


Incluir um novo elemento no início da lista é uma tarefa simples. Para isso, é
preciso ajustar o apontamento inicial da lista, que vai indicá-lo como primeiro
elemento, definindo como seu próximo elemento aquele que ocupava essa
posição anteriormente.
Antes de incluir um elemento no início da lista, é preciso alocar memória
e atribuir os dados do produto para a estrutura. Na sequência, fazemos o novo
elemento, que foi criado, apontar para o próximo do início da lista e o início
da lista apontar para o novo elemento.

Incluir no meio da lista


A inclusão de um elemento em uma posição intermediária deve ser realizada
pela varredura da lista até a posição desejada. Essa posição pode ser identi-
ficada, por exemplo, por algum atributo da estrutura, como a descrição do
produto.
Estrutura de Dados - II UNIDADE 2
6 Lista dinâmica Lista Dinâmica PARTE 9 213

Assim que a posição for identificada, é preciso ajustar os apontamentos


para manter a lista ligada e sequencial. Dessa forma, deve-se fazer o elemento
anterior apontar para o novo elemento e esse para o elemento que era o posterior.

Incluir no final da lista


Inserir um elemento no final da lista também é uma tarefa simples. Basta
percorrer a lista até a última posição e fazer com que o último elemento aponte
para o novo e este para NULL, pois o último elemento deve, obrigatoriamente,
apontar para NULL para indicar o final da lista.
214 ESTRUTURA DE DADOS
Lista dinâmica 7

Excluir no início da lista


Para excluir o elemento do início da lista, é preciso fazer com que a lista inicie
pelo elemento que era sucessor do elemento que foi excluído, além de liberar
a memória desse elemento que deixou de pertencer à lista.
Estrutura de Dados - II UNIDADE 2
8 Lista dinâmica Lista Dinâmica PARTE 9 215

Excluir no meio da lista


Para excluir um elemento que ocupa uma posição intermediária na lista dinâ-
mica, é preciso percorrer a lista até encontrar a posição desejada, identificando
o elemento anterior e o sucessor. A partir disso, basta fazer o anterior apontar
para o sucessor, além de liberar a memória que estava alocada para o elemento
que foi excluído.

Excluir no final da lista


Para excluir o elemento do final da lista, é necessário realizar uma varredura
na lista até chegar à última posição e definir o apontamento do penúltimo
elemento como NULL, bem como liberar a memória do elemento que ocupava
a última posição.
216 ESTRUTURA DE DADOS

Lista dinâmica 9

Excluir toda a lista


Para excluir uma lista dinâmica inteira, é preciso percorrê-la e liberar a alo-
cação de memória de todos os elementos, bem como indicar que o próximo
elemento de cada item aponte para NULL, garantindo, assim, a destruição
completa da lista.

Desenvolver funções de acesso a uma lista


dinâmica
As operações de acesso a uma lista dinâmica realizam as ações de leitura e
impressão sem aplicar qualquer modificação nos elementos. Essas operações
são consideradas ações de apoio à manipulação de dados, pois atuam sobre
os dados já inseridos na lista.
Podem ser criadas diversas operações de acesso a uma lista, sendo as
principais: verificar se a lista está vazia ou cheia, identificar o primeiro e o
último elementos, pesquisar um elemento em qualquer posição e imprimir a
relação completa de elementos da lista.
Estrutura de Dados - II UNIDADE 2
10 Lista dinâmica Lista Dinâmica PARTE 9 217

Verificar se a lista está vazia


Uma lista dinâmica está vazia se ela aponta para NULL. Isso significa que
nenhum elemento foi inserido ou que todos já foram excluídos. A função que
identifica se uma lista está vazia está descrita a seguir.

Acessar primeiro elemento da lista


Para acessar o primeiro elemento da lista, basta pegar o próximo elemento
do endereço da lista. Verificar se a lista está vazia é cabível para apresentar a
mensagem correta, no caso de a lista não conter elementos.
218 ESTRUTURA DE DADOS Lista dinâmica 11

Acessar último elemento da lista


Não é possível acessar diretamente o último elemento de uma lista dinâmica,
uma vez que o endereço de cada elemento só é conhecido pelo seu sucessor.
Com base nisso, é preciso percorrer toda a lista a partir do primeiro elemento.

Pesquisar elemento na lista


Sabendo que uma lista dinâmica não permite acessar diretamente os elementos,
é preciso realizar uma varredura na lista a partir da primeira posição. Dessa
forma, compara-se cada elemento da lista com o dado pesquisado, buscando
localizar a informação solicitada.
Estrutura de Dados - II UNIDADE 2
12 Lista dinâmica Lista Dinâmica PARTE 9 219

Imprimir toda a lista


Para imprimir a relação completa de elementos de uma lista dinâmica, é
necessário percorrê-la a partir da primeira posição, até que o último elemento
aponte para NULL.
220 ESTRUTURA DE DADOS

Lista dinâmica 13

CELES, W.; CERQUEIRA, R.; RANGEL, J. L. Introdução a estrutura de dados: com técnicas
de programação em C. Rio de Janeiro: Campus, 2004. 294 p.EDELWEISS, N.; GALANTE,
R. Estrutura de dados. Porto Alegre: Bookman, 2009. 262 p. (Série Livros Didáticos
Informática UFRGS, 18).
LORENZI, F.; MATTOS, P.; CARVALHO, T. Estruturas de dados. São Paulo: Cengage Le-
arning, 2007. 200 p.

Leituras recomendadas
DEITEL, P.; DEITEL, H. C: como programar. 6. ed. São Paulo: Pearson Education, 2011.
818 p.
FORBELLONE, A. L. V.; EBERSPÁCHER, H. F. Lógica de programação: a construção de
algoritmos e estruturas de dados. 3 ed. São Paulo, Pearson, 2005. 232 p.

PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.
PREZADO ESTUDANTE

ENCERRA AQUI O TRECHO DO LIVRO DISPONIBILIZADO


PELA SAGAH PARA ESTA PARTE DA UNIDADE.

CONTRIBUA COM A QUALIDADE DO SEU CURSO

Se você encontrar algum problema nesse material, entre em


contato pelo email eadproducao@unilasalle.edu.br. Descreva o
que você encontrou e indique a página.

Lembre-se: a boa educação se faz com a contribuição de todos!


Av. Victor Barreto, 2288
Canoas - RS
CEP: 92010-000 | 0800 541 8500
ead@unilasalle.edu.br

Você também pode gostar