Você está na página 1de 19

Programação II

Listas Encadeadas
(Linked Lists)

Bruno Feijó
Dept. de Informática, PUC-Rio
Vetores vs Estruturas Dinâmicas

• Vetores (arrays):
– Ocupa um espaço contíguo de memória
– Permite acesso randômico
– Requer pré-dimensionamento de espaço de memória
• Estruturas Dinâmicas
– Crescem (ou decrescem) à medida que elementos são inseridos (ou
removidos)
– Exemplo: Listas Encadeadas
– Outras estruturas:
• Pilhas
• Filas
Listas Encadeadas

• Lista Encadeada é uma sequência de elementos, onde cada


elemento tem uma informação armazenada (info) e um ponteiro
para o próximo elemento da sequência
lst
info1 info2 ... infoN NULL

• A maneira mais simples de representar uma lista é pelo ponteiro


para o primeiro elemento da sequência
– Usualmente chamado de “head”, “cabeça”, ou simplesmente “lst”
• O ponteiro do último elemento é NULL
• Estrutura recursiva (c/ponteiro para ela mesmo):
struct elemento struct elemento
{ {
int info; float info;
struct elemento * prox; struct elemento * prox;
}; };
typedef struct elemento Elemento; typedef struct elemento Elemento;
Lista de inteiros
novo insere no início !
lst
lista.c info1 info2
Elemento * lst_insere(Elemento * lst, int a)
{
Elemento * novo = (Elemento *)malloc(sizeof(Elemento));
if (novo != NULL)
{
novo->info = a;
novo->prox = lst; void lst_imprime(Elemento * lst)
} {
Elemento * p;
return novo; for (p = lst; p != NULL; p = p->prox)
} printf(“info = %d\n”, p->info);
prog.c }

int main (void)


{
Elemento * lst; // declara uma lista não inicializada
lst = NULL; // cria e inicializa lista como vazia
lst = lst_insere(lst, 23); // insere na lista o elemento 23
lst = lst_insere(lst, 45); // insere na lista o elemento 45
lst_imprime(lst);
return 0;
}
lst
45 23
NULL
Busca Sequencial

• Retorna o ponteiro do elemento da lista que contém a informação


procurada ou retorna NULL se não a encontrar

Elemento * busca (Elemento * lst, int v)


{
Elemento * p;
for (p=lst; p!=NULL; p = p->prox)
{
if (p->info == v)
return p;
}
return NULL; /* não achou o elemento */
}
Remover um Elemento
Elemento * lst_retira(Elemento * lst, int a)
{
Elemento * ant = NULL; /* ponteiro para elemento anterior */
Elemento * p = lst; /* ponteiro para percorrer a lista */
/* procura elemento na lista, guardando anterior */
while (p != NULL && p->info != a)
{
ant = p; lst

p = p->prox;
}
if (p == NULL)
return lst; /* não achou: retorna lista original */
/* retira elemento */
if (ant == NULL)
{ /* retira elemento do inicio */
lst = p->prox; }
else { /* retira elemento do meio da lista */
ant->prox = p->prox; } lst
free(p);
return lst;
a
}
Libera a Lista e Testa Igualdade
• Destrói a lista, liberando todos os elementos alocados
void lst_libera(Elemento * lst)
{
Elemento * p = lst, * t;
while (p != NULL) {
t = p->prox; /* guarda referência p/ próx. elemento */
free(p); /* libera a memória apontada por p */
p = t; /* faz p apontar para o próximo */
}
}

• Igualdade requer dois ponteiros


int lst_igual(Elemento * lst1, Elemento * lst2)
{
Elemento * p1; /* ponteiro para percorrer l1 */
Elemento * p2; /* ponteiro para percorrer l2 */
for (p1=lst1, p2=lst2; p1 != NULL && p2 != NULL;
p1 = p1->prox, p2 = p2->prox) Esta comparação considera o caso das
if (p1->info != p2->info) listas de tamanho diferente. Se os dois
return 0; chegaram ao NULL (ou já eram ambos NULL)
return p1==p2; significa que são do mesmo tamanho. Se um
} é NULL e o outro não, então têm tamanhos
diferentes!
Poderia também ser: return p1==NULL &&
p2==NULL;
Um Programa usando Lista Encadeada

#include <stdio.h>
#include "lista.h"
int main (void)
{
Elemento * lst; /* declara uma lista não iniciada */
lst=NULL; /* inicia lista vazia */
lst=lst_insere(lst,23); /* insere na lista o elemento 23 */
lst=lst_insere(lst,45); /* insere na lista o elemento 45 */
lst=lst_insere(lst,56); /* insere na lista o elemento 56 */
lst=lst_insere(lst,78); /* insere na lista o elemento 78 */
lst_imprime(lst); /* imprimirá: 78 56 45 23 */
lst=lst_retira(lst,78);
lst_imprime(lst); /* imprimirá: 56 45 23 */
lst=lst_retira(lst,45);
lst_imprime(lst); /* imprimirá: 56 23 */
...
lst_libera(lst);
return 0;
}
Insere Ordenado
Elemento * lst_insere_ordenado(Elemento * lst, int a)
{
Elemento * novo;
Elemento * ant = NULL; /* ponteiro para elemento anterior */
Elemento * p = lst; /* ponteiro para percorrer a lista */
/* procura posição de inserção */
while (p != NULL && p->info < a)
{ ant = p; p = p->prox; }
/* cria novo elemento */
novo = (Elemento *) malloc(sizeof(Elemento));
novo->info = a;
/* encadeia elemento */
if (ant == NULL)
{ /* insere elemento no início */
novo->prox = lst;
lst = novo; }
else { /* insere elemento no meio da lista */
novo->prox = ant->prox;
ant->prox = novo; }
return lst;
}
LISTAS – FUNÇÕES RECURSIVAS
Você pode usar diretamente
lst != NULL no lugar de
Funções de Lista Recursivas !lst_vazia(lst)
void lst_imprime(Elemento * lst)
int lst_vazia(Elemento * lst) {
if ( ! lst_vazia(lst)) {
{ printf(“info: %d\n”,lst->info); // 1º.
return (lst == NULL); lst_imprime(lst->prox);
} }
void lst_libera(Elemento * lst) }
{ void lst_imprimeInvertida(Elemento * lst)
if (!lst_vazia(lst)) {
{ if (!lst_vazia(lst))
{
lst_libera(lst->prox); lst_imprimeInvertida(lst->prox);
free(lst); printf(“info: %d\n”,lst->info);
} }
} }
int lst_igual(Elemento * lst1, Elemento * lst2)
{ Elemento * lst_retira(Elemento * lst, int a)
if (lst1 == NULL && lst2 == NULL) {
return 1; Elemento * t;
else if (lst1 == NULL || lst2 == NULL) if (!lst_vazia(lst)) {
return 0; if (lst->info == a) {
else t = lst;
return (lst1->info == lst2->info) && lst = lst->prox;
lst_igual(lst1->prox,lst2->prox); free(t);
} }
else {
lst_imprime lst->prox= lst_retira(lst->prox,a);
lst_imprimeInvertida }
lst_libera }
lst_igual return lst;
lst_retira }
LISTAS DE TIPOS ESTRUTURADOS
Listas de Tipos Estruturados
• A informação associada a cada elemento pode ser mais complexa, sem
alterar o encadeamento dos elementos
• As funções apresentadas para listas de inteiros podem ser facilmente
adaptadas para tratar listas de outros tipos (as diferenças são pequenas!)
• O campo de informação pode ser representado por um ponteiro para uma
estrutura, ao invés da estrutura em si. Desta maneira, independente da
informação armazenada na lista, a estrutura do elemento é sempre
composta por struct elemento
{
– um ponteiro para a informação e Aluno * info;
– um ponteiro para o próximo elemento da lista struct elemento * prox;
};
• Escolha nomes apropriados para as funções de serviço (mesmo não
sendo um TAD), e.g.: float aluno_obterMedia(Elemento * p) e int
aluno_obterFaltas(Elemento * p) para retornar a média e o número de
faltas de uma lista de alunos como um tipo estruturado:
struct aluno
{
float media;
int faltas;
};
Listas de Tipos Estruturados sem Ponteiros

• A alternativa que não usa um ponteiro para a informação deve incluir


todos os atributos da informação dentro da própria estrutra do elemento
de lista:
struct elemento
{
float media;
int faltas;
struct elemento * prox;
};

• Treine repetindo exercícios usando este tipo de definição de listas!


TÓPICOS AVANÇADOS
LISTAS COMO ESTRUTURAS
Lista como Estrutura (apropriado para TAD)
• Uma Lista pode ser uma estrutura contendo um ponteiro para o primeiro elemento
e um outro ponteiro para o último elemento. Esta forma é apropriada para TADs e
para Listas duplamente encadeadas. Isto também facilita a definição de lista vazia.
lst
first last

info1 info2 ... infoN NULL


struct lista
{
Elemento * first;
Elemento * last;
};
typedef struct lista Lista;
• Reescreva todas as funções já apresentadas (em slides e exercícios)
• note que uma lista é vazia quando os dois ponteiros são NULL
• Uma outra variante é incluir o número de elementos:
first last n
LISTAS CIRCULARES E
DUPLAMENTE ENCADEADAS
Listas Circulares e Duplamente Encadeadas
lst
• Listas Circulares Info1 Info2 Info3

• Listas Duplamente Encadeadas


lst
NULL
NULL Info1 Info2 Info3

Elemento2 * lst2_insere(Elemento2 * lst, int a)


{
Elemento2 * novo = (Elemento2 *) malloc(sizeof(Elemento2));
novo->info = a;
novo->prox = lst;
novo->ant = NULL; struct elemento2
/* verifica se lista não estava vazia */ {
if (lst != NULL) int info;
lst->ant = novo; struct elemento2 * ant;
return novo; struct elemento2 * prox;
} };
typedef struct elemento2 Elemento2;

Função busca é idêntica ao caso de lista encadeada simples


Implemente com [first,last] também.

Você também pode gostar