Anda di halaman 1dari 9

30/06/2017 Listas encadeadas

Projeto de Algoritmos | Linguagem C | ndice

Listas encadeadas

Uma lista encadeada uma representao de uma sequncia de objetos, todos do mesmo tipo, na memria
RAM (=random access memory) do computador. Cada elemento da sequncia armazenado em uma clula da
lista: o primeiro elemento na primeira clula, o segundo na segunda e assim por diante.

Estrutura de uma lista encadeada


Uma lista encadeada (=linked list =lista ligada) uma sequncia de clulas; cada clula contm um objeto de
algum tipo e o endereo da clula seguinte. Suporemos neste captulo que os objetos armazenados nas
clulas so do tipo int. Cada clula um registro que pode ser definido assim:
struct reg {
int conteudo;
struct reg *prox;
};

conveniente tratar as clulas como um novo tipo-de-dados e atribuir um nome a esse novo tipo:
typedef struct reg celula; // clula

Uma clula c e um ponteiro p para uma clula podem ser declarados assim:

celula c;
celula *p;

Se c uma clula ento c.conteudo o contedo da clula e c.prox o endereo da prxima clula. Se p
o endereo de uma clula, ento p->conteudo o contedo da clula e p->prox o endereo da prxima
clula. Se p o endereo da ltima clula da lista ento p->prox valeNULL.

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 1/9
30/06/2017 Listas encadeadas

(A figura pode dar a falsa impresso de que as clulas da lista ocupam posies consecutivas na memria.
Na realidade, as clulas esto tipicamente espalhadas pela memria de maneira imprevisvel.)

Exerccios 1
1. DECLARAO ALTERNATIVA. Verifique que a declarao de clulas tambm podem ser escrita assim:
typedef struct reg celula;
struct reg {
int conteudo;
celula *prox;
};

2. DECLARAO ALTERNATIVA. Verifique que a declarao de clulas tambm podem ser escrita assim:
typedef struct reg {
int conteudo;
struct reg *prox;
} celula;

3. TAMANHO DE CLULA. Compile e execute o seguinte programa:


int main (void) {
printf ("sizeof (celula) = %d\n", sizeof (celula));
return EXIT_SUCCESS;
}

Endereo de uma lista encadeada


O endereo de uma lista encadeada o endereo de sua primeira clula. Sele o endereo de uma lista,
convm dizer simplesmente

le uma lista encadeada.

(No confunda "le" com"1e"). A lista est vazia (ou seja, no tem clula alguma) se e somente se le == NULL.

Listas so animais eminentemente recursivos. Para tornar isso evidente, basta fazer a seguinte observao:
sele uma lista no vazia ento le->prox tambm uma lista. Muitos algoritmos sobre listas encadeadas
ficam mais simples quando escritos de maneira recursiva.

EXEMPLO. Aseguinte funo recursiva imprime o contedo de uma lista encadeadale:


void imprime (celula *le) {
if (le != NULL) {
printf ("%d\n", le->conteudo);
imprime (le->prox);
}
}

E aqui est a verso iterativa da mesma funo:


void imprime (celula *le) {
celula *p;
for (p = le; p != NULL; p = p->prox)
printf ("%d\n", p->conteudo);
}

Exerccios 2

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 2/9
30/06/2017 Listas encadeadas

1. Escreva uma funo que conte o nmero de clulas de uma lista encadeada. Faa duas verses: uma iterativa e
uma recursiva.
2. ALTURA. A altura de uma clula c em uma lista encadeada a distncia entre c e o fim da lista. Mais precisamente,
a altura de c o nmero de passos do caminho que leva de c at a ltima clula da lista. Escreva uma funo que
calcule a altura de uma dada clula.
3. PROFUNDIDADE. Aprofundidade de uma clula c em uma lista encadeada o nmero de passos do nico caminho
que vai da primeira clula da lista atc. Escreva uma funo que calcule a profundidade de uma dada clula.

Busca em uma lista encadeada


Veja como fcil verificar se um objeto x pertence a uma lista encadeada, ou seja, se igual ao contedo de
alguma clula da lista:

// Esta funo recebe um inteiro x e uma


// lista encadeada le de inteiros e devolve
// o endereo de uma celula que contm x.
// Se tal clula no existe, devolve NULL.

celula *
busca (int x, celula *le)
{
celula *p;
p = le;
while (p != NULL && p->conteudo != x)
p = p->prox;
return p;
}

Que beleza! Nada de variveis booleanas "de passagem" ou "de sinalizao"! Alm disso, a funo se
comporta bem mesmo que a lista esteja vazia.

Eis uma verso recursiva da mesma funo:

celula *buscaR (int x, celula *le)


{
if (le == NULL) return NULL;
if (le->conteudo == x) return le;
return buscaR (x, le->prox);
}

Exerccios 3
1. A funo abaixo promete ter o mesmo comportamento da busca acima. Critique o cdigo.
celula *busca (int x, celula *le) {
celula *p = le;
int achou = 0;
while (p != NULL && !achou) {
if (p->conteudo == x) achou = 1;
p = p->prox; }
if (achou) return p;
else return NULL; }

2. Critique o cdigo da seguinte variante da funo busca.


celula *busca (int x, celula *le) {
celula *p = le;
while (p != NULL && p->conteudo != x)
p = p->prox;

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 3/9
30/06/2017 Listas encadeadas
if (p != NULL) return p;
else printf ("x no est na lista\n"); }

3. Escreva uma funo que verifique se uma lista encadeada que contm nmeros inteiros est em ordem crescente.
4. Escreva uma funo que faa uma busca em uma lista encadeada crescente. Faa verses recursiva e iterativa.
5. Escreva uma funo que encontre uma clula com contedo mnimo. Faa duas verses: uma iterativa e uma
recursiva.
6. Escreva uma funo que verifique se duas listas encadeadas so iguais, ou melhor, se tm o mesmo contedo. Faa
duas verses: uma iterativa e uma recursiva.

7. PONTO MDIO. Escreva uma funo que receba uma lista encadeada e devolva o endereo de uma clula que esteja
o mais prximo possvel do meio da lista. Faa isso sem contar explicitamente o nmero de clulas da lista.

Cabea de lista
s vezes convm tratar a primeira clula de uma lista encadeada como um mero "marcador de incio" e
ignorar o contedo da clula. Nesse caso, dizemos que a primeira clula a cabea (=head cell =dummy cell)
da lista encadeada.

Uma lista encadeada le com cabea est vazia se e somente se le->prox == NULL. Para criar uma lista
encadeada vazia com cabea, basta dizer
celula *le;
le = malloc (sizeof (celula));
le->prox = NULL;

Para imprimir o contedo de uma lista encadeada le com cabea, faa

void imprima (celula *le) {


celula *p;
for (p = le->prox; p != NULL; p = p->prox)
printf ("%d\n", p->conteudo);
}

Exerccios 4
1. Escreva verses das funes busca e buscaR para listas encadeadas com cabea.
2. Escreva uma funo que verifique se uma lista encadeada com cabea est em ordem crescente. (Suponha que as
clulas contm nmeros inteiros.)

Insero em uma lista encadeada


Considere o problema de inserir (=to insert) uma nova clula em uma lista encadeada. Suponha que quero
inserir a nova clula entre a posio apontada por p e a posio seguinte. (claro que isso s faz sentido se
p diferente de NULL.)

// Esta funo insere uma nova celula


// em uma lista encadeada. A nova celula
// tem conteudo x e inserida entre a
// celula p e a clula seguinte.
// (Supe-se que p != NULL.)

void

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 4/9
30/06/2017 Listas encadeadas
insere (int x, celula *p)
{
celula *nova;
nova = mallocc (sizeof (celula));
nova->conteudo = x;
nova->prox = p->prox;
p->prox = nova;
}

Simples e rpido! No preciso movimentar clulas para "abrir espao" para um nova clula, como fizemos
para inserir um novo elemento em um vetor. Basta mudar os valores de alguns ponteiros.

O tempo que a funo insere consome no depende do ponto da lista em que feita a insero: tanto faz
inserir uma nova clula na parte inicial da lista quanto na parte final. Isso bem diferente do que ocorre com
a insero em um vetor.

Observe que a funo se comporta corretamente mesmo quando quero inserir no fim da lista, isto, quando
p->prox == NULL. Se a lista tem cabea, a funo pode ser usada para inserir no incio da lista: basta que p
aponte para a clula-cabea. Infelizmente, a funo no capaz de inserir antes da primeira clula de uma
lista sem cabea.

Exerccios 5
1. Por que a seguinte verso da funo insere no funciona?
void insere (int x, celula *p) {
celula nova;
nova.conteudo = x;
nova.prox = p->prox;
p->prox = &nova; }

2. Escreva uma funo que insira uma nova clula em uma lista encadeada sem cabea. (Ser preciso tomar algumas
decises de projeto antes de comear a programar.)
3. Escreva uma funo que faa uma cpia de uma lista encadeada. Faa duas verses da funo: uma iterativa e uma
recursiva.
4. Escreva uma funo que concatene duas listas encadeadas (isto, "engate" a segunda no fim da primeira). Faa
duas verses: uma iterativa e uma recursiva.
5. Escreva uma funo que insira em uma lista encadeada uma nova clula com contedo x imediatamente depois da
k-sima clula. Faa duas verses: uma iterativa e uma recursiva.

6. Escreva uma funo que troque de posio duas clulas de uma mesma lista encadeada.

7. Escreva uma funo que inverta a ordem das clulas de uma lista encadeada (a primeira passa a ser a ltima, a
segunda passa a ser a penltima etc.). Faa isso sem usar espao auxiliar, apenas alterando ponteiros. D duas
solues: uma iterativa e uma recursiva.
8. ALOCAO DE CLULAS. uma boa ideia alocar as clulas de uma lista encadeada uma-a-uma? (Veja observao
sobre alocao de pequenos blocos de bytes no captulo Alocao dinmica de memria.) Proponha alternativas.

Remoo em uma lista encadeada


Considere o problema de remover (=to remove =to delete) uma certa clula de uma lista encadeada. Como
especificar a clula em questo? A ideia mais bvia apontar para a clula que quero remover. Mas fcil
perceber que essa ideia no boa; melhor apontar para a clula anterior que quero remover.
(Infelizmente, no possvel remover a primeira clula usando essa conveno.)

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 5/9
30/06/2017 Listas encadeadas

// Esta funo recebe o endereo p de uma


// celula de uma lista encadeada e remove
// da lista a celula p->prox. A funo supe
// que p != NULL e p->prox != NULL.

void
remove (celula *p)
{
celula *lixo;
lixo = p->prox;
p->prox = lixo->prox;
free (lixo);
}

Veja que maravilha! No preciso copiar informaes de um lugar para outro, como fizemos para remover
um elemento de um vetor: basta mudar o valor de um ponteiro. A funo consome sempre o mesmo tempo,
quer a clula a ser removida esteja perto do incio da lista, quer esteja perto do fim.

Note tambm que a funo de remoo no precisa conhecer o endereo da lista, ou seja, no precisa saber
onde a lista comea.

Exerccios 6
1. Critique a seguinte verso da funo remove:
void remove (celula *p, celula *le) {
celula *lixo;
lixo = p->prox;
if (lixo->prox == NULL) p->prox = NULL;
else p->prox = lixo->prox;
free (lixo); }

2. Suponha que queremos remover a primeira clula de uma lista encadeada le no vazia. Critique o seguinte
fragmento de cdigo:
celula **p;
p = ≤
le = le->prox;
free (*p);

3. Invente um jeito de remover uma clula de uma lista encadeada sem cabea. (Ser preciso tomar algumas decises
de projeto antes de comear a programar.)
4. Escreva uma funo que desaloque (aplique a funo freea) todos os ns de uma lista encadeada. Estamos
supondo que cada clula da lista foi originalmente alocado por malloc. Faa duas verses: uma iterativa e uma
recursiva.
5. PROBLEMA DE JOSEPHUS. Imagine uma roda de n pessoas numeradas de 1 an no sentido horrio. Comeando com a
pessoa de nmero1, percorra a roda no sentido horrio e elimine cada m-sima pessoa enquanto a roda tiver duas
ou mais pessoas. Qual o nmero do sobrevivente?

Exerccios 7
1. Escreva uma funo que copie o contedo de um vetor para uma lista encadeada preservando a ordem dos
elementos. Faa duas verses: uma iterativa e uma recursiva.
2. Escreva uma funo que copie o contedo de uma lista encadeada para um vetor preservando a ordem dos
elementos. Faa duas verses: uma iterativa e uma recursiva.
3. UNIO. Digamos que uma lesc uma lista encadeada (sem cabea) que contm uma sequncia estritamente
crescente de nmeros inteiros. (Portanto, uma lesc representa um conjunto de nmeros.) Escreva uma funo que

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 6/9
30/06/2017 Listas encadeadas

faa a unio de duas lescs produzindo uma nova lesc. A lesc resultante deve ser construda com as clulas das
duas lescs dadas.
4. LISTAS ENCADEADAS SEM PONTEIROS. Implemente uma lista encadeada sem usar endereos e ponteiros. Use dois
vetores paralelos: um vetor conteudo[0..N-1] e um vetor prox[0..N-1]. Para cada i no conjunto 0..N-1,
opar (conteudo[i], prox[i]) representa uma clula da lista. Aclula seguinte (conteudo[j], prox[j]),
sendo j = prox[i]. Escreva funes de busca, insero e remoo para essa representao.
5. Esta questo trata de listas encadeadas que contm strings. Escreva uma funo que verifique se uma lista desse
tipo est em ordem lexicogrfica. As clulas so do seguinte tipo:
typedef struct reg {
char *str; struct reg *prox;
} celula;

6. CONTAGEM DE PALAVRAS. Digamos que um texto um vetor de bytes, todos com valor entre 32 e126. (Cada um
desses bytes representa um caracteres ASCII.) Digamos que uma palavra um segmento maximal de texto que
consiste apenas de letras. Escreva uma funo que receba um texto e imprima uma relao de todas as palavras
que ocorrem no texto juntamente com o nmero de ocorrncias de cada palavra. Use uma lista encadeada para
armazenar as palavras.

Busca e remove
Dada uma lista encadeada le de inteiros e um inteiroy, queremos remover da lista a primeira clula que
contivery. Se tal clula no existir, no preciso fazer nada. Para simplificar, vamos supor que a lista tem
cabea; assim, no ser preciso mudar o endereo da lista, mesmo que a clula inicial contenhay.
// Esta funo recebe uma lista encadeada le
// com cabea e remove da lista a primeira
// celula que contiver y, se tal celula existir.

void
busca_e_remove (int y, celula *le)
{
celula *p, *q;
p = le;
q = le->prox;
while (q != NULL && q->conteudo != y) {
p = q;
q = q->prox;
}
if (q != NULL) {
p->prox = q->prox;
free (q);
}
}

Para provar que o cdigo est correto, preciso verificar o seguinte invariante: no incio de cada iterao
(imediatamente antes da comparao de q com NULL), tem-se

q == p->prox,

ou seja, q est um passo frente dep.

Exerccios 8
1. Escreva uma funo busca-e-remove para listas encadeadas sem cabea.
2. Escreva uma funo para remover de uma lista encadeada todas as clulas que contmy.
3. Escreva uma funo que remova a k-sima clula de uma lista encadeada sem cabea. Faa duas verses: uma
iterativa e uma recursiva.

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 7/9
30/06/2017 Listas encadeadas

Busca e insere
Suponha dada uma lista encadeada le, com cabea. Queremos inserir na lista uma nova clula com
contedo x imediatamente antes da primeira clula que contm y .
// Esta funo recebe uma lista encadeada le
// com cabea e insere na lista uma nova celula
// imediatamente antes da primeira que contm y.
// Se nenhuma celula contm y, insere a nova
// celula no fim da lista. O conteudo da nova
// celula x.

void
busca_e_insere (int x, int y, celula *le)
{
celula *p, *q, *nova;
nova = mallocc (sizeof (celula));
nova->conteudo = x;
p = le;
q = le->prox;
while (q != NULL && q->conteudo != y) {
p = q;
q = q->prox;
}
nova->prox = q;
p->prox = nova;
}

Exerccios 9
1. Escreva uma funo busca-e-insere para listas encadeadas sem cabea.

Outros tipos de listas


Uma vez entendidas as listas encadeadas bsicas, voc pode inventar muitos outros tipos de listas
encadeadas.

Por exemplo, voc pode construir uma lista encadeada circular, em que a ltima clula aponta para a
primeira. O endereo de uma tal lista o endereo de uma de suas clulas (a ltima, por exemplo). Voc
pode tambm ter uma lista duplamente encadeada: cada clula contm o endereo da clula anterior e o
endereo da clula seguinte.

Pense nas seguintes questes, apropriadas para qualquer tipo de lista encadeada. Convm ter uma clula-
cabea e/ou uma clula-rabo? Em que condies a lista est vazia? Como remover a clula apontada por p?
Idem para a clula seguinte apontada por p? Idem para a clula anterior apontada por p? Como inserir
uma nova clula entre a clula apontada por p e a anterior? Idem entre p e a seguinte?

Exerccios 10
1. Descreva, em linguagem C, a estrutura de uma clula de uma lista duplamente encadeada.
2. Escreva uma funo que remova de uma lista duplamente encadeada a clula apontada porp. Que dados sua
funo recebe? Que coisa devolve?
3. Escreva uma funo que insira uma nova clula com contedo x em uma lista duplamente encadeada logo aps a
clula apontada porp. Que dados sua funo recebe? Que coisa devolve?
https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 8/9
30/06/2017 Listas encadeadas

Veja o verbete Linked list na Wikipedia

Atualizado em 2017-05-05
http://www.ime.usp.br/~pf/algoritmos/
Paulo Feofiloff
DCC-IME-USP

https://www.ime.usp.br/~pf/algoritmos/aulas/lista.html 9/9