You are on page 1of 10

Estruturas de Dados

Listas Dinâmicas
Simplesmente
Encadeadas
Prof. Ricardo J. G. B. Campello

Créditos
Parte dos slides a seguir são adaptações,
extensões e recodificações em C dos originais:
 disponíveis em http://ww3.datastructures.net/

 cedidos pela Profa. Maria Cristina F. de Oliveira

1
Listas Dinâmicas
 Utiliza alocação dinâmica de memória ao
invés de arranjos (vetores) pré-alocados.
 Lista dispõe de toda memória disponível para o
programa durante a execução (heap)

 Alocação/liberação desses endereços é


gerenciada pelo S.O., por meio de comandos
da linguagem de programação
 Linguagem C: malloc e free

Listas Simplesmente Encadeadas


Uma lista encadeada é uma
estrutura de dados linear que próximo
consiste de uma seqüência
interligada de nós (ou nodos)
dinamicamente alocados.
No caso de encadeamento
elemento nodo
simples, cada nodo armazena:
 elemento (registro, objeto, ...)
 ponteiro para o próximo nodo.

A B C D 4

2
Listas Simplesmente Encadeadas
nodo
 Nodo: lig
elem

struct list_node {
tipo_elem elem;
struct list_node *lig;
};
typedef struct list_node nodo;

Listas Simplesmente Encadeadas

nulo (NULL)

 Lista:
typedef struct {
int nelem;
nodo *head, *tail;
} Lista;
Lista L; /* Exemplo de Declaração */

3
Listas Simplesmente Encadeadas
 Inicialização:
nulo
(NULL)
Lista *Definir(void){
Lista *L;
L = malloc(sizeof(Lista));
L->nelem = 0;
L->head = NULL;
L->tail = NULL;
return L;
}

Inserindo no Início
1. Aloque o novo nodo.
2. Insira o novo elemento.
3. Aponte o novo nodo
para head.
4. Aponte head para o
novo nodo.

PS. símbolo ∅ representa NULL.

4
Inserindo no Início
nodo *Inserir_frente(tipo_elem x, Lista *L){
nodo *Pa;
Pa = malloc(sizeof(nodo));
Pa->elem = x;
Pa->lig = L->head;
L->head = Pa;
if (L->tail == NULL) /* L antes vazia */
L->tail = L->head;
L->nelem++;
return Pa;
} /* O(1) */

Removendo do Início
1. Aponte um ponteiro
auxiliar Pa para head

2. Aponte head para o


próximo nodo.

3. Desaloque o primeiro
nodo usando Pa

10

5
Removendo do Início
tipo_elem Remover_frente(Lista *L){
tipo_elem x;
nodo *Pa;
Pa = L->head;
L->head = Pa->lig;
if (L->head == NULL) /* L antes com elemento único */
L->tail = NULL;
x = Pa->elem;
free(Pa);
L->nelem--;
return x;
} /* O(1) */
11

Inserindo no Final
1. Aloque o novo nodo.
2. Insira o novo elemento.
3. Faça o novo nodo
apontar para NULL.
4. Faça o antigo último
nodo apontar para o
novo.
5. Atualize tail para o novo
nodo.
Podemos inverter a ordem
dos passos 4 e 5 ?
12

6
Inserindo no Final
nodo *Inserir_final(tipo_elem x, Lista *L){
nodo *Pa;
Pa = malloc(sizeof(nodo));
Pa->elem = x;
Pa->lig = NULL;
if (L->head == NULL) L->head = Pa; /* L antes vazia */
else (L->tail)->lig = Pa;
L->tail = Pa;
L->nelem++;
return Pa;
} /* O(1) */

13

Removendo do Final
Remover no final de uma lista
simplesmente encadeada não
é eficiente.

Não existe algoritmo de


complexidade (tempo)
constante para acessar o
nodo anterior a tail.

A obtenção a partir de head é


O(n), onde n é o número de
elementos na lista (nelem na
nossa implementação).

14

7
Removendo do Final
tipo_elem Remover_final(Lista *L){
tipo_elem x;
nodo *Pa;
Pa = L->head;
if ((L->head)->lig == NULL) { /* L com 1 elemento */
L->tail = NULL;
L->head = NULL; }
else {
while (Pa->lig != L->tail) Pa = Pa->lig;
L->tail = Pa;
Pa = Pa->lig;
(L->tail)->lig = NULL; }
x = Pa->elem; free(Pa);
L->nelem--;
return x; } /* O(L.nelem) */

Exercícios
1. Implemente uma função Lista_vazia(Lista *L) que retorna
True ou False se a lista está vazia ou não, respectivamente
2. Seja o tipo dos elementos da lista, tipo_elem, definido como
um registro (struct) com dois campos: chave e info
1.a. Implemente a seguinte função:
retorno Localizar(tipo_elem x, Lista *L);
que retorna um registro do tipo retorno, também com dois
campos:
 Campo 1 (int): Rank do elemento com chave x.chave na lista L
 Campo 2 (nodo*): Ponteiro para o nodo de x em L

1.b. Qual o tempo de execução assintótico (BIG-O) de pior caso?


3. Faz sentido aqui Localizar via Busca Binária? Justifique

8
Exercícios
4. Implemente funções para remover elementos quaisquer da lista:
tipo_elem Remover_elem(tipo_elem x, Lista *L);

tipo_elem Remover_rank(int p, Lista *L);

 A 1a deve remover da lista o nodo que armazena o elemento com


chave x.chave (retornando ao sistema a respectiva memória) e
retornar esse elemento
 A 2a deve fazer o mesmo, mas para o p-ésimo elemento da lista

5. Repita o exercício anterior para as funções Buscar_elem e


Buscar_rank, que apenas retornam o elemento, sem remover
o respectivo nodo da lista
6. Implemente uma função Modificar que substitua o elemento
em uma dada colocação (rank) da lista por outro, retornando-o
17

Exercícios
7. Implemente uma função Modify que substitua um dado
elemento x com chave x.chave por outro y também dado.
Use Localizar do exercício 1 e Modificar do exercício 5
8. Suponha que se disponha de um ponteiro para um dado nodo
da lista (por exemplo obtido via Localizar do exercício 1):
 Explique porque, mesmo com esse ponteiro em mãos, não
é possível remover o respectivo nodo em tempo constante
O(1) (sem ter que percorrer a lista a partir de head)
 É possível modificar a ED dos nodos para tornar isso
possível? Justifique
9. Faça um procedimento Esvaziar(Lista *L) que devolva a
memória de todos os nodos de uma lista L ao sistema e
reinicialize a lista
18

9
Bibliografia
A. M. Tenembaum et al., Data Structures Using C,
Prentice-Hall, 1990
M. T. Goodrich & R. Tamassia, Data Structures and
Algorithms in C++/Java, John Wiley & Sons,
2002/2005

N. Ziviani, Projeto de Algoritmos, Thomson, 2a.


Edição, 2004
J. L. Szwarcfiter & L. Markenzon, Estruturas de
Dados e seus Algoritmos, LTC, 1994
Schildt, H. "C Completo e Total", 3a. Edição,
Pearson, 1997
19

10

You might also like