Você está na página 1de 84

/39

1/84


MCTA028-15: Programação Estruturada

Aula 8: Listas

Francisco de Assis Zampirolli e Wagner Tanaka Botelho


fzampirolli@ufabc.edu.br / wagner.tanaka@ufabc.edu.br / wagtanaka@gmail.com
Universidade Federal do ABC (UFABC)
Centro de Matemática, Computação e Cognição (CMCC)
2/84

Introdução
3/84

Introdução
 Na Ciência da Computação, uma lista:
 É uma estrutura de dados linear utilizada para armazenar e organizar
dados em um computador;
 É uma sequência de elementos do MESMO tipo;
 Pode possuir N (N>=0) elementos ou itens;
 Se N=0, a lista está VAZIA.
44 10 3 99
 Vamos estudar:
 Lista sequencial estática (primeira parte);
 Lista dinâmica encadeada (segunda parte).
4/84

Alocação de Memória
5/84

Alocação de Memória
 Alocação estática:
 Espaço de memória é alocado no momento da compilação do
programa;
 É necessário definir o NÚMERO MÁXIMO de elementos que a lista irá
possuir.
 Alocação dinâmica:
 Espaço de memória é alocado em TEMPO DE EXECUÇÃO;
 A lista CRESCE à medida que novos elementos são armazenados;
 A lista DIMINUI à medida que elementos são removidos.
6/84

Acesso aos Elementos


7/84

Acesso aos Elementos


 Acesso sequencial:
 Os elementos são armazenados de forma consecutiva na memória (como um
array ou vetor);
 A posição de um elemento pode ser facilmente obtida a partir do ÍNDICE da lista.

 Acesso encadeado:
 Cada elemento pode estar em uma área distinta da memória, não
necessariamente consecutivas;
 É necessário que cada elemento da lista armazene, além da sua informação, o
endereço de memória onde se encontra o PRÓXIMO elemento;
 Para acessar um elemento, é preciso PERCORRER todos os seus antecessores na
lista.
8/84

Operações Básicas
9/84

Operações Básicas
 Independente do tipo de alocação e acesso, as seguintes
operações básicas podem ser implementadas:
 Criação da lista;
 Inserção de um elemento na lista;
 Remoção de um elemento na lista;
 Busca por um elemento da lista;
 Destruição da lista;
 Informações sobre tamanho, se a lista está cheia ou vazia, etc.
10/84

Lista Sequencial Estática


11/84

Lista Sequencial Estática


 Uma lista sequencial estática ou lista linear estática é uma lista definida utilizando
ALOCAÇÃO ESTÁTICA e ACESSO SEQUENCIAL dos elementos;
 Considerado o tipo mais SIMPLES de lista possível;

 Definida utilizando um array, de modo que o sucessor de um elemento ocupe a sua


posição física seguinte;
 Além do array, a lista utiliza um CAMPO ADICIONAL (qtd) que serve para indicar o quanto
do array já está ocupado pelos elementos inseridos na lista.
qtd 0
0 1 2 3 4
num
tamArray-1
12/84

Lista Sequencial Estática: Vantagens e Desvantagens


 Vantagens:
 Acesso rápido e direto aos elementos (índice do array);
 Facilidade para modificar as suas informações;
 ......

 Desvantagens:
 Definição prévia do tamanho do array e, consequentemente, da lista;
 Dificuldade para inserir e remover um elemento entre outros dois:
 É necessário deslocar os elementos para abrir espaço dentro do
array.
13/84

Lista Sequencial Estática: Quando Utilizar?


 Em geral, utiliza-se nas seguintes situações:
 Listas pequenas;
 Inserção e remoção apenas no final da lista;
 Tamanho máximo da lista bem definido;
 ....
14/84

Definindo o Tipo
15/84

Lista Sequencial Estática: Definindo o Tipo


 Antes de implementar a lista, é necessário definir o TIPO
DE DADO que será armazenado nela;
 Um ponteiro deve ser criado para a estrutura que define
a lista.
Ex_4.c 16/84

Definindo uma constante (tamanho do


array).
Definindo o tipo lista com dois
campos:
+ qtd (int): indica quantidade de
OU elementos inseridos na lista
+ array num do tipo int: tipo de
dado a ser armazenado na lista.
Redefinindo a struct para
encurtar o comando.
17/84

Criando a Lista
18/84
Ponteiro para estrutura lista. Alocando a área de
memória para a
lista.
= (*li).qtd=0; armazena a quantidade de
elementos inseridos na lista.

qtd 0
0 1 2 3 4
Lista *li;
num
tamArray-1
19/84

“Destruindo” a Lista
20/84

Liberando a memória alocada para a estrutura


que representa a lista.

qtd
Lista *li;
num
0 tamArray-1
21/84

Tamanho da Lista
22/84

tam = li->qdt; Indica o quanto do array já está ocupado pelos


qtd 4 elementos inseridos na lista.

num 12 5 10 55
0 tamArray-1
Para saber o tamanho da lista, basta retornar o
valor de qtd.

Se for verdade, algum problema aconteceu na


criação da lista.
tam = (*li).qtd;
tam recebe o valor de qtd, ou seja, o tamanho
da lista.
23/84

Lista Cheia
24/84
Lista Cheia:
li->qdt == tamArray
qtd tamArray

num 12 5 10 55 44
0 tamArray-1
Se ocorreu algum problema na criação da lista, o valor
retornado será -1.
A variável qtd também é utilizada para
saber se a lista está cheia. Basta veri-
ficar se qtd = ao tamanho do array
(tamArray).
Se a lista não estiver cheia, o valor
retornado será 0.
25/84

Lista Vazia
26/84

qtd Lista Vazia:


0
li->qdt == 0
num
0 tamArray-1

Se ocorreu algum problema na criação da lista, o


valor retornado será -1.
A variável qtd também é utilizada para saber
se a lista está vazia. Basta verificar se
qtd = 0.
Se a lista não estiver vazia, o valor
retornado será 0.
27/84

Inserindo na Lista
28/84
Se ocorreu algum problema na criação da lista, o
valor retornado será 0.
Se a lista estiver cheia, o valor retorna-
do será 0.
Inserindo na próxima posição livre do
array.
Incrementando a quantidade de elementos.

qtd 021

li->num[0]=12 num 12 5
insere_lista(pList, 12);
li->qtd++ 0 tamArray-1
insere_lista(pList, 5); li->num[1]=5
li->qtd++
29/84

Inserindo no Final da Lista


30/84

Inserindo no Final da Lista


 Diferente da inserção no início, a inserção no FINAL de
uma lista sequencial estática NÃO necessita que se mude
o lugar dos demais elementos da lista;
 Deve-se inserir o elemento após a última posição
ocupada do array que representa a lista.
31/84
Se ocorreu algum problema na criação da lista, o
valor retornado será 0.

Se a lista estiver cheia, o valor retorna-


do será 0.
Inserindo na próxima posição livre
do array.
Incrementando a quantidade de elementos.

qtd 2

num 12 5 10
0 tamArray-1
li->num[2]=10
insere_lista(pList, 10);
li->qtd++
32/84

Inserindo no Início da Lista


33/84

Inserindo no Início da Lista


 A inserção no início de uma lista sequencial
qtd 3
estática necessita que se mude o lugar dos
demais elementos da lista:
num 12 12
5 5
10 10
 Isso deixa o início da lista (a posição ZERO do
0 1 2 3
array) livre para inserir um novo elemento.
 Todos elementos da lista devem ser
PERCORRIDOS e COPIADOS para uma posição
para frente:
 Isso deve ser feito do ÚLTIMO ELEMENTO até
o PRIMEIRO, evitando, assim, que a cópia de
um elemento sobrescreva o outro.
Linha i n li->num[]
/84
insere_lista_inicio(pList, 77); 91 2
92 [3]=10
91 1
92 [2]=5
91 0
92 [1]=12
i = (*li).qtd-1; 91 -1
Desloca os elementos
uma posição para
Insere o elemento frente.
no início da lista.

qtd 4
3

77
num 12 5
12 10
5 10
0 1 2 3 tamArray-1
35/84

Removendo do Início da Lista


36/84

Removendo do Início da Lista


 Como na inserção, a remoção de um elemento do início de uma
lista sequencial estática necessita que se mude o lugar dos
demais elementos da lista;
 Basicamente, deve-se movimentar todos os elementos da lista
uma POSIÇÃO PARA TRÁS dentro do array:
 Esta ação sobrescreve o início da lista (a posição ZERO do
array);
 Ao mesmo tempo, a quantidade de elementos diminuiu.
Linha k n li->num[]
37/84
remove_lista_inicio(pList); 126 0
127 [0]=12
126 1
127 [1]=5
126 2
127 [2]=10
126 3
Desloca os elementos
uma posição para trás.
Deve-se diminuir em uma unidade a quanti-
dade de elementos armazenados na lista.

qtd 34 O último elemento da lista fica


duplicado. Entretanto, esta
77
num 12 12
5 10
5 10 posição é considerada NÃO
0 1 2 3 tamArray-1 ocupada por elementos na lista.
38/84

Removendo do Final da Lista


39/84

Removendo do Final da Lista


 Diferente da remoção do início, a remoção do final de
uma lista sequencial estática não necessita que se mude
o lugar dos demais elementos da lista:
 Entretanto, deve-se alterar a quantidade de elementos na
lista.
 O elemento removido continua no final da lista:
 Isso não é um problema, pois a posição é considerada não
ocupada por elementos da lista.
remove_lista_final(pList); 40/84

Alterar a quantidade de elementos na lista.

qtd 32 O elemento removido continua no


final da lista. Entretanto, esta posição
num 12 5 10 é considerada NÃO ocupada por
0 1 2 3 tamArray-1 elementos na lista.
41/84

Removendo um Elemento Específico da Lista


42/84

Removendo um Elemento Específico da Lista


 Deve-se procurar o elemento a ser removido na lista, o qual
pode estar no início, no meio ou no final da lista:
 No início ou meio, é preciso mudar, após a remoção, o lugar dos
demais elementos da lista.
 Basicamente, deve-se procurar o elemento da lista e
movimentar TODOS os elementos que estão à frente na lista
uma posição para trás dentro do array:
 Isso sobrescreve o elemento a ser removido, ao mesmo tempo que
diminui o número de elementos.
43/84

Procurando o elemento
(elem) no array.
Se verdade, o elemento não foi encontrado
no array.
Desloca os elementos uma
posição para trás.
remove_lista_elemento(pList, 10);
44/84
Linha i k elem li->num[]
151 0 0
161 1
161 2
166 2
167 [2]=4
166 3

qtd 4
3

num 12 5 10
4 4
0 1 2 3 tamArray-1
45/84

Busca por Posição na Lista


46/84

Se o ponteiro li==NULL ou posição buscada (pos) é negativa ou


posição (pos) é maior que o tamanho da lista.
resp recebe o elemento armazenado
na posição (pos) recebida como
parâmetro.

qtd 3
busca_lista_pos(pList, 2); resp = li->num[1]
num 12 5 4
0 1 2 3 tamArray-1
47/84

Busca por Conteúdo na Lista


48/84
busca_lista_pos(pList, 5);

Procurando o
elemento (elem)
no array.
Se verdade, o elemento não foi encontrado no
array.

Elemento encontrado, a sua posição é retornada.


Linha i resp li->qtd li->num[]
qtd 3
187 0 0
192 3 12
num 12 5 4
193 1
0 1 2 3 tamArray-1
200 1
49/84

Lista Dinâmica Encadeada


50/84

Introdução
 Uma lista dinâmica encadeada é uma lista definida utilizando alocação dinâmica e
acesso encadeado dos elementos;
 Cada elemento da lista é alocado dinamicamente, à medida que os dados são
inseridos dentro da lista, e tem sua memória liberada, à medida que é removido;
 Cada elemento é um ponteiro para uma estrutura contendo dois campos de
informação:
 CAMPO DE DADO: é utilizado para armazenar a informação inserida na lista;
 CAMPO PROX: é um ponteiro que indica o próximo elemento na lista.
pro
dado NULL
x
51/84

Introdução
 A lista dinâmica encadeada utiliza um PONTEIRO para PONTEIRO
para guardar o PRIMEIRO elemento da lista:
 O ponteiro para ponteiro é utilizado para representar o
INÍCIO da lista.
 TODOS os elementos são ponteiros alocados dinamicamente.
Inicio

23 2 15 NULL
52/84

Introdução
 Vantagens:
 Melhor utilização dos recursos de memória;
 Não é preciso definir previamente o tamanho da lista;
 Não é necessário movimentar os elementos nas operações de
inserção e remoção.
 Desvantagens:
 Acesso indireto aos elementos;
 Necessidade de percorrer a lista para acessar determinado
elemento.
53/84

Definindo o Tipo
pro
numero Definindo o tipo que descreve cada elemento da
54/84

x
lista.
+ *prox: ponteiro para o próximo elemento da
lista;
+ numero: tipo de dado (int) a ser armazenado
na lista.
Redefinindo a struct para encurtar o
comando.

Lista *li; É um ponteiro para Lista que já é um ponteiro para a struct


elemento. Portanto, li é um ponteiro para ponteiro. Por ser ponteiro
para ponteiro, li armazena o endereço de um ponteiro.
Inicio (li)

pro
numero

x
55/84

Criando a Lista
Alocando uma área de memória 56/84

para armazenar o endereço do


início da lista.
li é um ponteiro para ponteiro
O conteúdo de li é NULL, indicando que não existe
nenhum elemento alocado após o atual, ou seja, a
lista esta vazia.

Lista *li; Início NULL


57/84

“Destruindo” a Lista
58/84
Se a lista foi criada com sucesso.

Cada elemento da lista é


percorrido, enquanto conteúdo
do INÍCIO da lista for diferente de
NULL.

Inicio (*li) Inicio (*li) Inicio (*li) Inicio (*li)

23 2 15 NULL

nó nó nó
59/84

Tamanho da Lista
60/84

Tamanho da Lista
 Diferente da lista sequencial estática, para saber o
tamanho da lista dinâmica, é preciso PERCORRER toda a
lista, CONTANDO os elementos inseridos nela, até
encontrar o seu final.
61/84

Verifica se a lista foi criada com sucesso.

Nó aponta para o início da lista.


Percorre a lista até o valor do nó for
diferente de NULL (fim da lista).

Início (*li)

cont = 3
0
2
1 23 2 15 NULL

nó nó nó nó
62/84

Lista Cheia
63/84

Lista Cheia
 Na lista dinâmica encadeada somente será considerada
CHEIA quando NÃO tiver mais memória disponível para
alocar novos elementos:
 Apenas ocorrerá quando a chamada da função
malloc() retornar NULL.
64/84

Lista Vazia
65/84

Lista Vazia
 Uma lista dinâmica encadeada é considerada VAZIA
sempre que o conteúdo do seu “INÍCIO” apontar para a
constante NULL.
66/84
Verifica se a lista foi criada com sucesso.

Acessa o conteúdo do início (*li) para comparar


com NULL.
Se a lista estiver vazia.

Lista não vazia.

Lista Vazia!!!
Início (*li) NULL
Início (*li) Lista Não Vazia!!!

23 2 NULL
67/84

Inserindo no Início da Lista


68/84

Inserindo no Início da Lista


 Diferente da lista sequencial estática, a inserção no inicio de
uma lista dinâmica encadeada NÃO necessita que se mude o
lugar dos demais elementos da lista;
 Basicamente, deve-se alocar espaço para o novo elemento da
lista e mudar os valores de alguns ponteiros.
69/84
Verifica se a lista foi criada com sucesso.

Se não foi possível alocar memória.

Copiando (para o nó) o número recebido


como parâmetro.
Nó está apontando para o início (*li).
Conteúdo do início da lista (*li) recebe o nó.
Início (*li) Início (*li)
no no
12 12 23 2 NULL
70/84

Inserindo no Final da Lista


71/84

Inserindo no Final da Lista


 Como na inserção no início, a INSERÇÃO no FINAL de
uma lista dinâmica encadeada não necessita que se
mude o lugar dos demais elementos da lista:
 Entretanto, é preciso percorrer a lista toda para
descobrir o ÚLTIMO elemento e assim fazer a inserção
após ele.
Conteúdo de li está apontando para NULL
72/84

(lista vazia)?
Verificar se a inserção é possível.
Ponteiro aux recebe o endereço da primeira
posição da lista (li).

no
99 NULL
Início (*li)

23 2 15 NULL
99 NULL

aux aux aux aux


73/84

Removendo do Início da Lista


74/84

Removendo do Início da Lista


 Diferente da lista sequencial estática, a REMOÇÃO do
início de uma lista dinâmica encadeada NÃO necessita
que se mude o lugar dos demais elementos da lista.
75/84

Verificar se a remoção é possível.

Ponteiro no recebe o endereço da primeira


posição da lista (li).

Início (*li) Início (*li)

23 2 15 NULL

no
76/84

Removendo do Fim da Lista


77/84

Verificar se a remoção é possível.

Último elemento da lista pode ser o único.

Início (*li)

2 15 NULL

ant no no
78/84

Removendo um Elemento Específico da Lista


79/84

Verificar se a remoção é possível.

Não encontrou o elemento (elem) na lista.

Remover o primeiro elemento da lista.

remove_lista(ptList, 2);
Início (*li)

23 2 15 NULL

ant no no
80/84

Busca por Posição na Lista


81/84
A lista está vazia ou a posição é
negativa?

busca_lista_posicao(ptList, 2);
pos = 2;
i=2
1

resp = 88;
Não encontrou o elemento na lista.
Início (*li)

23 88 15 NULL

no no no
82/84

Busca por Conteúdo na Lista


83/84
Se aconteceu algum problema na criação da lista.

Busca_lista_conteudo(ptList, 15);
conte = 15;
i = 13
2
Retorna a posição
(i=3) que se encontra o
elemento buscado.

Não encontrou o elemento na lista.


Início (*li)

23 88 15 NULL

no no no no
84/84

Referências
 Slides do Prof. Luiz Rozante;

 SALES, André Barros de; AMVAME-NZE, Georges. Linguagem C: roteiro de


experimentos para aulas práticas. 2016;
 BACKES, André. Linguagem C Completa e Descomplicada. Editora Campus. 2013;

 SCHILDT, Herbert. C Completo e Total. Makron Books. 1996;

 DAMAS, Luís. Linguagem C. LTC Editora. 1999;

 DEITEL, Paul e DEITEL, Harvey. C Como Programar. Pearson. 2011;

 BACKES, André. Estrutura de Dados Descomplicada em Linguagem C. GEN LTC.


2016.

Você também pode gostar