Вы находитесь на странице: 1из 25

ESTRUTURAS DE DADOS

Listas

SUMRIO
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Definio Ponteiros Alocao de memria Implementao Busca seqencial Memria livre Criao de lista Destruio de lista Insero e remoo Problemas com ponteiros Pilhas e Filas Listas circulares Listas duplamente encadeadas Concluses

1. Definio
Uma lista um arranjo seqencial de elementos. Dada uma lista L, as seguintes operaes so tpicas Encontrar o primeiro elemento de L Dado um elemento de L, encontrar o prximo ou o anterior Encontrar o k-simo elemento da lista Arrays so listas onde os elementos so de mesmo tamanho e armazenados contiguamente na memria do computador Vamos agora considerar listas encadeadas. Estas no tm as principais restries dos arrays: possvel inserir ou remover elementos em O(1) O problema de overflow no existe, ou melhor, acontece apenas quando a memria do computador se esgota Listas encadeadas tambm tm desvantagens: Utilizam mais memria que arrays (par elemento/elo) Acesso direto - i.e., O(1) - ao k-simo elemento no possvel

2. Ponteiros
Listas (encadeadas) so usualmente implementadas com variveis ponteiros. Uma (varivel) ponteiro contm um endereo de memria. Esse endereo a posio de uma outra varivel na memria. Diz-se que o ponteiro aponta para essa varivel. Por exemplo, se uma varivel x na posio 1004 apontada por uma varivel y na posio 1000, ento a posio 1000 contm o valor 1004 e a varivel y (da posio 1000) um ponteiro para a varivel x (da posio 1004). Por exemplo, na linguagem C, tem-se os seguintes conceitos bsicos para uso de uma varivel ponteiro: int *p; declara uma varivel ponteiro p para inteiros p = # coloca o endereo da varivel num em p q = *p; coloca o valor da varivel apontada por p em q

2. Ponteiros
Exemplo em C
#include <stdio.h> int main(void) { int num, q; int *p; /* declara ponteiro p para inteiros */

num = 100; /* num recebe o valor 100 */ p = &num; /* p recebe o endereco de num */ q = *p; /* q recebe o valor de num indiretamente por meio de p */ printf("%d \n", q); system("pause"); return 0; } /* imprime 100 */

3. Alocao de memria
Um assunto muito intimamente ligado a estruturas encadeadas a alocao de memria. Esta consiste no processo de solicitar/utilizar memria para o processo de execuo de um programa de computador. A alocao de memria pode ser dividida em dois grupos principais: 1) Alocao Esttica: os dados tm um tamanho fixo e esto organizados seqencialmente na memria do computador. Um exemplo tpico de alocao esttica so os arrays; 2) Alocao Dinmica (alocao encadeada): os dados no precisam ter um tamanho fixo, pois podemos definir para cada dado quanto de memria que desejamos usar. Sendo assim vamos alocar espaos de memria (blocos) que no precisam estar necessariamente organizados de maneira seqencial, podendo estar distribudos de forma esparsa na memria do computador. Um exemplo tpico de alocao encadeada so as listas encadeadas; Na alocao dinmica, vamos pedir para alocar/desalocar blocos de memria, de acordo com a nossa necessidade, reservando ou liberando blocos de memria durante a execuo de um programa. Para poder achar os blocos esparsos na memria usamos as variveis do tipo Ponteiro.

4. Implementao
Elementos so armazenados na memria em endereos arbitrrios Ordem seqencial entre os elementos armazenada explicitamente (elos, ponteiros, links) Deve ser possvel determinar o elo correspondente a cada elemento (p.ex., armazenamento consecutivo usando 2 elos) A lista propriamente s pode ser acessada sabendo-se o endereo do seu primeiro elemento Deve haver alguma maneira de determinar o comprimento da lista (p.ex., elo nulo, comprimento armazenado)

L L[1] L[2] L[n]

4. Implementao
Vamos assumir: Cada n (par elemento/elo) armazenado em posies contguas de memria Usamos um elo nulo para indicar o fim da lista Uma lista referida por um elo que leva ao primeiro n da lista Sendo assim, vamos propositalmente confundir o conceito de elo e lista.

5. Busca Seqencial
Vamos usar a seguinte notao: Nulo : elo (lista) nulo L: denota o elo que leva ao primeiro n da lista (ou a prpria lista) L^.Elo: denota o elo do primeiro n da lista, ou seja, indica o prximo n da lista. L^.Elemento: denota o elemento armazenado no primeiro n da lista

proc Busca (Lista L, Valor v) /* verso recursiva */ { se L = Nulo ento retornar falso seno se L^.Elemento = v ento retornar verdadeiro seno retornar Busca (L^.Elo, v) }

5. Busca Seqencial
Vamos usar a seguinte notao: tmp: denota um iterador de lista. Isso quer dizer que ele recebe o elo da lista (ou a prpria lista) . Ele serve para percorrer a lista.

proc Busca (Lista L, Valor v) /* verso no recursiva */ { tmp L enquanto tmp Nulo fazer { se tmp^.Elemento = v ento retornar verdadeiro seno tmp tmp^.Elo } retornar falso }

6. Memria Livre
preciso haver algum mecanismo que permita gerenciar a memria livre Quando se quer alocar um n, requisita-se uma rea contgua de memria livre suficientemente grande Aloca(Tipo) retorna um elo para uma rea de memria grande suficiente para guardar uma estrutura de dados do tipo Tipo Ex.: Aloca(NoLista) retorna um elo para um n de lista, isto , uma Lista Quando uma rea de memria no est mais em uso, ela retornada ao gerenciador para ser reutilizada posteriormente Libera(Elo) retorna (devolve, libera) a rea de memria contgua apontada por Elo

6. Memria Livre
Em linguagem C, voc pode alocar e liberar memria usando as rotinas da biblioteca padro malloc( ), que aloca memria e retorna um ponteiro void* para o incio dela, e free( ) que retorna (libera) a memria anteriormente alocada. Ambas as rotinas usam o arquivo de cabealho stdlib.h Exemplo: o fragmento a seguir aloca 1.000 bytes de memria.o ponteiro p (para tipo char) aponta para o incio da memria livre. Em seguida, a memria liberada. char *p; p = malloc(1000); free(p);

Como observao, para a compatibilidade com C++, seria preciso fazer a converso de tipo no fragmento acima, ficando: p = (char *) malloc(1000);

6. Memria Livre
Um outro exemplo: o fragmento a seguir aloca memria para 50 inteiros. O ponteiro p aponta para o incio dessa memria. Em seguida, a memria liberada. int *p; p = malloc(50*sizeof(int)); ou (int *) malloc(50*sizeof(int)); free(p); Se no houver espao livre na memria para atender solicitao, malloc( ) retorna um valor nulo. preciso, preventivamente, testar para saber se a memria foi alocada. O trecho a seguir faz isso. int *p; if ((p =(int *) malloc(100) == NULL) printf(Falta de memria \n)

7. Criao de Lista
Para criar uma lista com um nico elemento igual a v proc CriaListaUnaria (Valor v) { L Aloca (NoLista) L^.Elemento v L^.Elo Nulo retornar L } L v

Para criar uma lista com um elemento igual a v frente de uma lista S S

proc CriaNoLista (Valor v, Lista S) { L Aloca (NoLista) L^.Elemento v L^.Elo S retornar L }

L v

8. Destruio de lista
Para destruir o primeiro n de uma lista proc DestroiNoLista (var Lista L ) L { tmp L L L^.Elo Libera (tmp) }

DestroiNoLista (L)

tmp L

Obs: Note que na rotina, L um parmetro varivel, isto , passado por referncia.

L tmp
Libera (tmp)

L L^.Elo

L tmp

L tmp ?

8. Destruio de lista
Para destruir uma lista inteira proc DestroiLista (var Lista L) { enquanto L Nulo fazer DestroiNoLista (L) } Obs: Note que na rotina, L um parmetro varivel, isto , passado por referncia.

9. Insero e Remoo
Todos os procedimentos de insero e remoo de elementos de uma lista encadeada podem ser escritos com o auxlio das rotinas CriaNoLista e DestroiNoLista Rotina para inserir um elemento v numa lista ordenada L proc InsereListaOrdenada (Valor v, var Lista L) { se L = Nulo ento L CriaListaUnria (v) seno se L^.Elemento > v ento L CriaNoLista (v, L) seno InsereListaOrdenada (v, L^.Elo) }

9. Insero e Remoo
Rotina para remover um elemento igual a v de uma lista ordenada L

proc RemoveListaOrdenada (Valor v, var Lista L) { se L Nulo ento se L^.Elemento = v ento DestroiNoLista (L) seno RemoveListaOrdenada (v, L^.Elo) }

10. Problemas com Ponteiros


Ponteiro no vazio (dangling pointer): Um ponteiro acaba apontando para uma rea de memria no mais sob controle do programa, ou Um ponteiro acaba apontando para uma rea qualquer de memria do programa sem que o programador se d conta. Vazamento de memria (memory leak): Uma rea de memria alocada para o programa esquecida por um programa. Em alguns casos, se o procedimento repetido muitas vezes, o programa acaba falhando por falta de memria.

10. Problemas com ponteiros


Muitas linguagens de programao (e.x., Java, LISP, Modula-3) aliviam esses problemas adotando o princpio da Coleta de Lixo (Garbage Collection): O programador aloca memria explicitamente mas no a libera explicitamente. Variveis que no so mais necessrias (e.x., saem de escopo), so entregues a um procedimento automtico (coletor de lixo) que se encarrega de devolv-las ao banco de memria livre. O coletor de lixo s devolve a varivel ao banco de memria livre se ela no pode mais ser acessada, isto , se nenhum ponteiro do programa aponta para ela. O esquema mais usado para se implementar coletores de lixo o do contador de referncias.

10. Problemas com ponteiros


A cada varivel alocada dinamicamente associado um contador de referncias, isto , um inteiro que indica o nmero de ponteiros que apontam para a varivel. Quando o contador de referncias chega a 0 (zero), a varivel dinmica retornada (liberada) para o banco de memria livre.

11. Pilhas e Filas


Uma lista encadeada ideal para ser usada na implementao de pilhas j que insero e remoo podem ser feitas com naturalidade em O(1) no incio da lista. Para implementar uma fila necessrio manter dois ponteiros: um para o incio e outro para o fim da fila. Enfileirar (no final da fila) e Desenfileirar (do incio da fila) so naturalmente O(1).

Enfileira

Incio

Fim Desenfileira

Incio

Fim Incio Fim

12. Listas Circulares


O uso de dois ponteiros tem que ser cuidadoso para contemplar os casos especiais onde a fila tem 0 ou 1 elemento Uma soluo mais elegante usar listas circulares Neste caso, utiliza-se apenas um ponteiro para o fim da fila e fica implcito que o incio da fila o n seguinte.

c c d a b

Desenfileira d Fim Enfileira d e Fim

Fim Incio

13. Listas Duplamente Encadeadas


Para implementar deques, precisamos ser capazes de seguir a seqncia de ns em ambos os sentidos Para tanto, utiliza-se listas duplamente encadeadas Cada n possui dois elos, um apontando para o n seguinte e outro para o n anterior Tambm neste caso podemos denotar o incio e o fim da cadeia explicitamente ou utilizando listas circulares

a Incio

c Fim

14. Concluses

Faa sempre o seu melhor ! FIM

Вам также может понравиться