You are on page 1of 6

' p == NULL ou p->prox uma lista.

. Listas com cabea e sem cabea Uma lista encadeada pode ser organizada de duas maneiras diferentes, um bvia e ou tra menos bvia. Lista com cabea. O contedo da primeira clula irrelevante: ela serve apenas para ma rcar o incio da lista. A primeira clula a cabea (= head cell = dummy cell) da list a. A primeira clula est sempre no mesmo lugar na memria, mesmo que a lista fique v azia. Digamos que ini o endereo da primeira clula. Ento ini->prox == NULL se e s omente se a lista est vazia. Para criar uma lista vazia, basta dizer celula c, *ini; c.prox = NULL; ini = &c; ou celula *ini; ini = malloc (sizeof (celula)); ini->prox = NULL;

Lista sem cabea. O contedo da primeira clula to relevante quanto o das demais. Ness e caso, a lista est vazia se o endereo de sua primeira clula NULL. Para criar uma lista vazia basta fazer celula *ini; ini = NULL;

[Veja observao sobre alocao de pequenos blocos de bytes na pgina "Alocao dinmica de a".] Suporemos no que segue que nossas listas tm cabea. O caso de listas sem cabea ser tr atado nos exerccios. Eu prefiro listas sem cabea (porque so mais "puras"), mas a vi da do programador fica mais fcil quando a lista tem cabea. Exemplos Eis como se imprime o contedo de uma lista encadeada com cabea: // Imprime o contedo de uma lista encadeada // com cabea. O endereo da primeira clula ini. void imprima (celula *ini) { celula *p; for (p = ini->prox; p != NULL; p = p->prox) printf ("%d\n", p->conteudo); } Eis a correspondente funo para lista sem cabea: // Imprime o contedo de uma lista encadeada ini. // A lista no tem cabea. void imprima (celula *ini) { celula *p; for (p = ini; p != NULL; p = p->prox) printf ("%d\n", p->conteudo); }

Busca em uma lista encadeada Veja como fcil verificar se um inteiro 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 de inteiros. O endereo da lista ini e ela tem uma celula-cabea. A funo devolve o endereo de uma celula que contm x. Se tal celula no existe, a funo devolve NULL.

celula *busca (int x, celula *ini) { celula *p; p = ini->prox; while (p != NULL && p->conteudo != x) p = p->prox; return p; } Que beleza! Nada de variveis booleanas! A funo se comporta bem at mesmo quando a lis ta est vazia. Eis uma verso recursiva da mesma funo: celula *busca2 (int x, celula *ini) { if (ini->prox == NULL) return NULL; if (ini->prox->conteudo == x) return ini->prox; return busca2 (x, ini->prox); } Exerccios Critique a funo abaixo. Ao receber uma lista encadeada com cabea e um inteiro x, el a promete devolver o endereo de uma clula com contedo x. Se tal clula no existe, prom ete devolver NULL. celula *busca (int x, celula *ini) { int achou; celula *p; achou = 0; p = ini->prox; while (p != NULL && !achou) { if (p->conteudo == x) achou = 1; p = p->prox; } if (achou) return p; else return NULL; }

Escreva uma verso da funo busca para listas sem cabea. [Mnimo] Escreva uma funo que encontre uma clula de contedo mnimo. Faa duas verses: iterativa e uma recursiva. Escreva uma funo que faa um busca em uma lista crescente. Faa verses para listas com e sem cabea. Faa verses recursiva e iterativa. [Ponto mdio de uma lista] Escreva uma funo que receba uma lista encadeada e devolv a o endereo de um n que esteja o mais prximo possvel do meio da lista. Faa isso sem c ontar explicitamente o nmero de ns da lista. Verificao do tamanho. Compile e execute o seguinte programa: typedef struc cel celula; struct cel {

int conteudo; celula *prox; }; int main (void) { printf ("sizeof (celula) = %d\n", sizeof (celula)); return 0; } Insero em uma lista Quero inserir (= insert) uma nova clula com contedo x entre a posio apontada por p e a posio seguinte [por que seguinte e no anterior?] em uma lista encadeada. clar o 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 apontada por p e a seguinte. Supe-se que p != NULL.

void insere (int x, celula *p) { celula *nova; nova = mallocX (sizeof (celula)); nova->conteudo = x; nova->prox = p->prox; p->prox = nova; } Veja que maravilha! No preciso movimentar clulas para "criar espao" para um nova clu la, como fizemos para inserir um elemento de um vetor. Basta mudar os valores de alguns ponteiros. Observe tambm que da lista, isto , da para inserir no ente, a funo no a funo se comporta corretamente mesmo quando quero inserir no fim quando p->prox == NULL. Se a lista tem cabea, a funo pode ser usa incio da lista: basta que p aponte para a clula-cabea. Infelizm capaz de inserir antes da primeira clula de uma lista sem cabea.

O tempo que a funo consome no depende do ponto da lista onde quero fazer a insero: ta nto 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. Exerccios Por que a seguinte verso de insere no funciona? void insere (int x, celula *p) { celula nova; nova.conteudo = x; nova.prox = p->prox; p->prox = &nova; } Escreva uma funo que insira um novo elemento em uma lista encadeada sem cabea. Ser p reciso tomar algumas decises de projeto antes de comear a programar. Remoo em uma lista Suponha que quero remover (= to remove = to delete) uma certa clula da lista. Com o posso especificar a clula em questo? A ideia mais bvia apontar para a clula que qu ero remover. Mas fcil perceber que essa ideia no boa. melhor apontar para a clula nterior que quero remover. Infelizmente, isso traz uma nova dificuldade: no h como pedir a remoo da primeira clula. Portanto, vamos nos limitar s listas com cabea.

Vamos supor que p o endereo de uma clula de uma lista com cabea e que desejo remove r a clula apontada por p->prox. (Note que a funo de remoo no precisa saber onde a li ta comea.)

// // // //

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

void remove (celula *p) { celula *morta; morta = p->prox; p->prox = morta->prox; free (morta); } Veja que maravilha! No preciso copiar informaes de um lugar para outro, como fizemo s para remover um elemento de um vetor: basta mudar o valor de um ponteiro. A fu no consome sempre o mesmo tempo, quer a clula a ser removida esteja perto do incio d a lista, quer esteja perto do fim. Exerccios Critique a seguinte verso da funo remove: void remove (celula *p, celula *ini) { celula *morta; morta = p->prox; if (morta->prox == NULL) p->prox = NULL; else p->prox = morta->prox; free (morta); }

Invente um jeito de remover uma clula de uma lista encadeada sem cabea. (Ser precis o tomar algumas decises de projeto antes de comear a programar.) Mais exerccios Escreva uma funo que copie um vetor para uma lista encadeada. Faa duas verses: uma i terativa e uma recursiva. Escreva uma funo que copie uma lista encadeada para um vetor. Faa duas verses: uma i terativa e uma recursiva. Escreva uma funo que faa uma cpia de uma lista dada. Escreva uma funo que concatena duas listas encadeadas (isto , "amarra" a segunda no fim da primeira). Escreva uma funo que conta o nmero de clulas de uma lista encadeada. Escreva uma funo que remove a k-sima clula de uma lista encadeada sem cabea. Escreva uma funo que insere na lista uma nova clula com contedo x entre a k-sima e a k+1-sima clulas. Escreva uma funo que verifica se duas listas dadas so iguais, ou melhor, se tm o mes mo contedo. Faa duas verses: uma iterativa e uma recursiva. Escreva uma funo que desaloca (funo free) todos os ns de uma lista encadeada. Estamo s supondo, claro, que cada n da lista foi originalmente alocado por malloc. Escreva uma funo que inverte 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 altere os ponteiros. D duas solues: uma iterativa e uma recursiva . Projeto de Programao. Digamos que um texto um vetor de caracteres contendo apenas letras, espaos e sinais de pontuao. Digamos que uma palavra um segmento maximal de texto que consiste apenas de letras. Escreva uma funo que recebe um texto e impri me uma relao de todas as palavras que ocorrem no texto juntamente com o nmero de oc orrncias de cada palavra. Outros tipos de listas A partir de agora, tudo festa: voc pode inventar uma grande variedade de tipos de listas encadeadas. Por exemplo, voc pode fazer uma lista encadeada circular: a l tima clula aponta para a primeira. A lista pode ou no ter uma clula-cabea (voc decide ). Para especificar uma lista circular, basta fornecer um endereo (por exemplo, o

endereo da ltima clula).

Outro tipo til a lista duplamente encadeada: cada clula contm o endereo da clula an erior e o da clula seguinte. A lista pode ou no ter uma clula-cabea (voc decide). A l ista pode at ter uma clula-rabo se voc achar isso til! Pense nas seguintes questes, apropriadas para qualquer tipo de lista encadeada. E m que condies a lista est vazia? Como remover a clula apontada por p? Idem para a clu la seguinte apontada por p? Idem para a clula anterior apontada por p? Como inser ir uma nova clula entre o elemento apontado por p e o seu antecessor? Idem entre p e seu sucessor? Exerccios Descreva, em linguagem C, a estrutura de uma das clula de uma lista duplamente en cadeada. Escreva uma funo que remove de uma lista duplamente encadeada a clula apontada por p. (Que dados sua funo recebe? Que coisa devolve?) Escreva uma funo que insira em uma lista duplamente encadeada, logo aps a clula apon tada por p, uma nova clula com contedo y. (Que dados sua funo recebe? Que coisa devo lve?) Problema de Josephus. Imagine que temos n pessoas dispostas em crculo. Suponha q ue as pessoas esto numeradas 1 a n no sentido horrio. Comeando com a pessoa de nmero 1, percorra o crculo no sentido horrio e elimine cada m-sima pessoa enquanto o crcu lo tiver duas ou mais pessoas. Qual o nmero do sobrevivente? Busca-e-remoo Suponha que ini o endereo de uma lista encadeada com cabea. Nosso problema: Dado um inteiro y, remover da lista a primeira clula que contm y (se tal clula no existe , no preciso fazer nada). // Esta funo recebe uma lista encadeada ini, // com cabea, e remove da lista a primeira // celula que contiver y, se tal celula existir. void buscaEremove (int y, celula *ini) { celula *p, *q; p = ini; q = ini->prox; while (q != NULL && q->conteudo != y) { p = q; q = q->prox; } if (q != NULL) { p->prox = q->prox; free (q); } } Invariante: no incio de cada iterao (imediatamente antes da comparao de q com NULL), temos q == p->prox , ou seja, q est sempre um passo frente de p. Exerccios Escreva uma funo busca-e-remove para listas encadeadas sem cabea (s pra ver que dor de cabea isso d). Busca-e-insero Mais uma vez, suponha que tenho uma lista encadeada ini, com cabea. ( bvio que ini diferente de NULL.) Nosso problema: Inserir na lista uma nova clula com contedo

x imediatamente antes da primeira clula que tiver contedo y ; se tal clula no exist e, inserir x no fim da lista. // // // // // // Esta funo recebe uma lista encadeada ini, com cabea, e insere na lista uma nova celula imediatamente antes da primeira que contiver y. Se nenhuma celula contm y, insere a nova celula no fim da lista. O conteudo da nova celula x.

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

You might also like