Estruturas de Dados e Algoritmos Listas Ligadas Estruturas de Dados e Algoritmos 26/03/2017 Fábio Lopes Caversan
Listas Ligadas Desvantagens do armazenamento seqüencial para representar pilhas e filas: Subdimensionamento ou superdimensionamento da memória devido a alocação fixa de uma certa quantidade de memória antes da execução do programa Possibilidade de overflow 26/03/2017 Fábio Lopes Caversan
Compartilhando a memória disponível Suponha uma implementação seqüencial de pilhas Stack x,y,z; Suponha que sejam inicializadas, de forma estática, com 50 elementos x,y,z terão, durante a utilização, respectivamente, no máximo, 20, 10 e 70 elementos 26/03/2017 Fábio Lopes Caversan
Fazendo cálculos 100 células seriam necessárias Porém, na inicialização, deve-se usar o tamanho 70 para não ocorrer um overflow Então, temos 3* 70 = 210,quando somente 100 serão utilizadas Que tal evitar esse desperdício através de um gerenciador de memória? Ele controlaria quem recebe mais ou menos células de memória 26/03/2017 Fábio Lopes Caversan
Agrupando as células livres num banco de memória livre Banco de memória Variáveis x y z nada nada nada 26/03/2017 Fábio Lopes Caversan
Operação Banco de memória x y z x.Push(a) (nada) (nada) y.Push(b) (nada) y.Push(c) (nada) x.Push(d) (nada) z.Push(e) (nada) 26/03/2017 Fábio Lopes Caversan
Operação Banco de memória x y z z.Push(f) (nada) y.Pop() z.Pop() (nada) x.Pop() (nada) z.Push(g) 26/03/2017 Fábio Lopes Caversan
Considerações importantes A ordem das células de memória disponíveis no banco, no decorrer da execução da aplicação, muda substancialmente O importante é manter um controle sobre a ordem lógica das células de memória e não, necessariamente, sobre a ordem física 26/03/2017 Fábio Lopes Caversan
Lista Ligada (Encadeada) Linear Cada item na lista é um nó Todo nó contem dois campos: o de informação e do endereço seguinte Campo de informação: armazena o real elemento da lista Campo de endereço: endereço do próximo nó na lista. É um ponteiro! 26/03/2017 Fábio Lopes Caversan
Algumas representações do nó ... Endereço do próximo nó Informação nulo 26/03/2017 Fábio Lopes Caversan
Continuando . . . A lista ligada inteira é acessada a partir de um ponteiro externo que aponta para o primeiro nó da lista Um ponteiro externo não está incluindo dentro de um nó. É acessado por referência a uma variável O campo do próximo endereço do último nó da lista contém um valor especial: null O ponteiro nulo (null) marca o final da lista Uma lista sem nós é uma lista vazia ou nula Nesse caso, o ponteiro externo para a lista é nulo Uma lista pode ser inicializada por uma operação do tipo list = null (sendo list o ponteiro externo) 26/03/2017 Fábio Lopes Caversan
Revisando o mapa conceitual de um programa na memória Endereços de retorno de funções, variáveis locais Pilha Heap Variáveis Globais Código do Programa Alocação dinâmica: listas encadeadas 26/03/2017 Fábio Lopes Caversan
Ao “fotografar” a memória do computador Área Livre (Heap) Programa LIST Ponteiro externo que aponta para o primeiro nó da lista ligada. Cuidado com sua manipulação! 26/03/2017 Fábio Lopes Caversan
. . . N1 Nn null N2 N3 L Dois endereços merecem atenção especial: O endereço L do nó inicial que permite identificar em que parte da memória inicia-se a lista O endereço NULL que vem após o nó final. É onde termina a lista Sempre lembrando, cada nó i é composto de duas partes: Info: área onde é armazenado o i-ésimo elemento da lista Next: área onde é armazenado o “endereço” do nó N i + 1 26/03/2017 Fábio Lopes Caversan
Declarando uma classe Nó para uma lista ligada Um dos atributos da classe precisa ser um ponteiro para uma estrutura do mesmo tipo public class Node { private object info; private Node next; ... }; 26/03/2017 Fábio Lopes Caversan
Permitindo o acesso aos atributos De acordo com a linguagem, pode ser necessária a escrita de métodos para ler e escrever nos atributos, garantindo o encapsulamento. Nas linguagens que possuem propriedades, isso pode ser feito com os comandos get e set. Cada vez que atribuímos um valor para a propriedade, o set é chamado. Cada vez que lemos um valor da propriedade, o get é chamado. 26/03/2017 Fábio Lopes Caversan
public class Node { private object info; private Node next; public object Info { get {return info;} set {info = value;} } public Node Next { get {return next;} set {next = value;} ... }; 26/03/2017 Fábio Lopes Caversan
Incluindo um elemento no início da lista info next info next info next list 5 8 nulo 3 p info next info next info next list 5 3 8 nulo 6 p info next info next info next 5 3 8 nulo list 26/03/2017 Fábio Lopes Caversan
6 5 3 8 nulo p list p 6 5 3 8 nulo list 6 5 3 8 nulo list 26/03/2017 Fábio Lopes Caversan
Os passos anteriores são expressos pelo seguinte algoritmo Node p = new Node(); p.Info = x; p.Next = list; list = p; 26/03/2017 Fábio Lopes Caversan
Removendo um nó do início de uma lista 7 5 9 nulo 9 nulo info next info next info next list P X=7 P list 26/03/2017 Fábio Lopes Caversan
Node p = list; list = p.Next; x = p.Info; Os passos anteriores para remover um nó são expressos pelo seguinte algoritmo Node p = list; list = p.Next; x = p.Info; 26/03/2017 Fábio Lopes Caversan
Implementação ligada de Pilhas Incluir um elemento no início de uma lista ligada é semelhante à inclusão numa pilha O 1º nó da lista representa o topo da pilha Vantagem: todas as pilhas ou filas usadas por um programa podem compartilhar a mesma lista de nós disponíveis, desde que não ultrapassam a quantidade total de nós disponíveis 26/03/2017 Fábio Lopes Caversan
Uma pilha usando lista ligada stack 7 nulo 5 3 8 stack 7 nulo 5 3 8 6 26/03/2017 Fábio Lopes Caversan
Como o 1º nó da lista é o topo da lista A implementação de Push (x) poderia ficar: Node p = new Node( ); p.Info = x; p.Next = stack; stack = p; 26/03/2017 Fábio Lopes Caversan
A implementação de x = pop (s) poderia ficar : if (Empty ()) // Exception, mensagem, etc... else { Node p = stack; stack = p.Next; x = p.Info; p = null; return x; } 26/03/2017 Fábio Lopes Caversan
Uma fila usando lista ligada final início 3 nulo 1 7 9 4 final início 6 nulo 7 9 3 4 1 26/03/2017 Fábio Lopes Caversan
Algoritmo para x = q.Remove () if (Empty()) // Exceção, mensagem, etc... Node p = front; x = p.Info; front = p.Next; if (front = = null) rear = null; p = null; return ( x ); A fila q consiste numa fila e dois ponteiros: front e rear. As operações q.Empty() e x=q.Remove() são análogas a s.Empty(s) e x=s.Pop(s), basta substituir front por stack. Muita atenção ao remover o último elemento da fila: rear fica também nulo porque se a fila está vazia front e rear devem ser nulos 26/03/2017 Fábio Lopes Caversan
Algoritmo para q.Insert (x) Node p = new Node(); p.Info = x; p.Next = null; if (rear = = null ) front = p; else rear.Next = p; rear = p; 26/03/2017 Fábio Lopes Caversan
Desvantagens de pilhas e filas como listas ligadas? Mais armazenamento do que o vetor: Info e Next Mas o espaço de armazenamento não é o dobro. Depois, pode-se compactar as informações Cada inclusão/exclusão corresponde a uma inclusão/exclusão na lista de nós disponíveis Grande vantagem: compartilhamento de nós, desde que não ultrapasse o número de nós disponíveis 26/03/2017 Fábio Lopes Caversan
Listas ligadas como estruturas de dados São importantes não só para implementar pilhas e filas, mas como estruturas de dados Acessa-se um item percorrendo-se a lista a partir do início Um vetor permite o acesso direto ao enésimo item com uma única operação Já uma lista exige n operações e é necessário percorrer cada um dos primeiros n-1 elementos antes do enésimo Vantagem da lista: aparece na inserção ou remoção de um elemento porque não é necessário nenhuma movimentação dos n elementos 26/03/2017 Fábio Lopes Caversan
Inserção de um novo elemento num vetor x0 x1 x2 x3 x4 x5 x0 x1 x2 x3 x4 x5 x0 x1 x2 x x3 x4 x5 x6 26/03/2017 Fábio Lopes Caversan
Já numa lista o trabalho de inserção independe do seu tamanho X0 X1 X2 X3 X4 nulo n list X0 X1 X2 X3 X4 nulo InsertAfter (n,x) Node p = new Node() p.Info = x; p.Next = n.Next; n.Next = p DeleteAfter(n) Node p = n.Next; x = p.Info; n.Next = p.Next; p = null; X 26/03/2017 Fábio Lopes Caversan