Listas encadeadas - João Araujo
Transcrição
Listas encadeadas - João Araujo
Estruturas de Informação I - Aula 12 Listas encadeadas João Araujo Ribeiro [email protected] Universidade do Estado do Rio de Janeiro Departamento de Engenharia de Sistemas e Computação João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 1 / 33 Resumo 1 EI12 - Listas Encadeadas 2 EI12 - Pilha como Lista Encadeada 3 EI12 - Fila como Lista Encadeada 4 EI12 - Lista Encadeada Circular 5 EI12 - Lista Duplamente Encadeada João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 2 / 33 EI12 - Listas Encadeadas Listas Encadeadas Vimos anteriormente os diversos tipos de listas possíveis. Neste capítulo vamos nos aprofundar na programação e uso de listas encadeadas João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 3 / 33 EI12 - Listas Encadeadas Lista Simplesmente encadeada Uma lista simplesmente encadeada é uma coleção de nós que coletivamente formam uma sequência linear. João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 4 / 33 EI12 - Listas Encadeadas Head e Tail O primeiro nó é conhecido como João Araujo Ribeiro (UERJ) Head e o último como Tail. Estruturas de Informação I EstrInf 5 / 33 EI12 - Listas Encadeadas Inserção no início da lista João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 6 / 33 EI12 - Listas Encadeadas Algoritmo de inserção no início 1 2 3 4 5 6 Algoritmo insere_inicio(L, e): newest = Node(e) {cria um novo nó para armazenar o elemento e} newest.next = L.head {aponta a próxima referência do novo nó para o antigo nó head} L.head = newest {Aponta head para o novo nó} L.size = L.size + 1 {incrementa o contador de nós} João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 7 / 33 EI12 - Listas Encadeadas Inserção no m da lista eencadeada João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 8 / 33 EI12 - Listas Encadeadas Algoritmo de inserção no m 1 2 3 4 5 6 Algoritmo insere_fim(L, e): newest = Node(e) {cria novo nó para armazenar elemento e} newest.next = None {Faz o próximo apontar para None} L.tail.next = newest {Faz antigo próximo de tail apontar para o novo nó} L.tail = newest {faz a variável tail apontar para novo nó} L.size = L.size + 1 {incrementa o contador de nós} João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 9 / 33 EI12 - Listas Encadeadas Remover elemento de lista encadeada João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 10 / 33 EI12 - Listas Encadeadas Algoritmo de remoção 1 2 3 4 5 Algorithm remove_primeiro(L): if L.head is None then Indica erro: a lista está vazia. L.head = L.head.next {faz head apontar para o próximo} L.size = L.size - 1 {decrementa contador} João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 11 / 33 EI12 - Listas Encadeadas Removendo último Infelizmente não podemos remover o último elemento tão facilmente. Mesmo mantendo um ponteiro para o último elemento, numa lista encadeada simples devemos começar de head e atravessar a lista inteiramente para atingir o último elemento. Este problema não haveria se a lista fosse duplamente encadeada. João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 12 / 33 EI12 - Pilha como Lista Encadeada Implementando uma pilha como lista encadeada Como base, implementamos uma classe _Node 1 2 3 4 5 6 class _Node: """Classe não publica para armazenar um nó.""" __slots__ = _element , _next def init (self, element, next): self._element = element self._next = next João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 13 / 33 EI12 - Pilha como Lista Encadeada Pilha como lista encadeada 1/3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class LinkedStack: """Implementação LIFO de Pilha usando lista encadeada.""" #-------------------------- Classe Node -------------------------class _Node: """Classe não pública para armazenar um nó.""" __slots__ = _element , _next def __init__(self, element, next): # carrega nó self._element = element # referência para elemento do usuário self._next = next # referência para o próximo nó #------------------------------- métodos da Pilha ----------------------def __init__ (self): """Cria pilha vazia.""" self._head = None # referência para head self._size = 0 # numero de elementos def __len__ (self): """Retorna o número de elementos na pilha.""" return self._size João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 14 / 33 EI12 - Pilha como Lista Encadeada Pilha como lista encadeada 2/3 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 def is_empty(self): """Retorna True se a pilha está vazia.""" return self._size == 0 def push(self, e): """Adiciona element e no topo da pilha.""" self._head = self._Node(e, self._head) # cria novo nó self._size += 1 def top(self): """Retorna (mas não remove) o elemento do topo da pilha. Levanta exceção Empty se pilha está vazia. """ if self.is_empty( ): raise Empty(Pilha Vazia) return self._head._element # topo da pilha éa cabeça da lista João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 15 / 33 EI12 - Pilha como Lista Encadeada Pilha como lista encadeada 3/3 38 39 40 41 42 43 44 45 46 47 def pop(self): """Remove e retorna o elemento do topo da pilha. Levanta exceção Empty se pilha está vazia. """ if self.is_empty( ): raise Empty(Pilha Vazia) answer = self._head._element self._head = self._head._next self._size -= 1 return answer João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 16 / 33 EI12 - Fila como Lista Encadeada Fila como lista encadeada 1/3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class LinkedQueue: """Implementação FIFO de Fila usando lista encadeada.""" #-------------------------- Classe Node -------------------------class _Node: """Classe não pública para armazenar um nó.""" __slots__ = _element , _next def __init__(self, element, next): # carrega nó self._element = element # referência para elemento do usuário self._next = next # referência para o próximo nó #------------------------------- métodos da Fila ----------------------def __init__ (self): """Cria fila vazia.""" self._head = None self._tail = None self._size = 0 # numero de elementos def __len__ (self): """Retorna o número de elementos na fila.""" return self._size João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 17 / 33 EI12 - Fila como Lista Encadeada Fila como lista encadeada 2/3 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 def is_empty(self): """Retorna True se a fila está vazia.""" return self._size == 0 def first(self): """Retorna (mas não remove) o elemento da frente da fila.""" if self.is_empty( ): raise Empty(Fila Vazia) return self._head._element def dequeue(self): """Remove e retorna o elemento do frente da fila. Levanta exceção Empty se fila está vazia.. """ if self.is_empty( ): raise Empty(Fila Vazia) João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 18 / 33 EI12 - Fila como Lista Encadeada Fila como lista encadeada 3/3 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 answer = self._head._element self._head = self._head._next self._size -= 1 if self.is_empty( ):# caso especial fila vazia self._tail = None return answer def enqueue(self, e): """Adiciona elemento ao fim da fila.""" newest = self._Node(e, None) # nó será o novo tail if self.is_empty( ): self._head = newest # caso especial: previamente vazia else: self._tail._next = newest self._tail = newest self._size += 1 João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 19 / 33 EI12 - Lista Encadeada Circular Lista Encadeada Circular João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 20 / 33 EI12 - Lista Encadeada Circular Lista Encadeada Circular sem início nem m João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 21 / 33 EI12 - Lista Encadeada Circular Fila Circular como lista encadeada 1/3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class CircularQueue: """Implementação de Fila como lista encadeada circular.""" class _Node: """Classe não publica para armazenar um nó.""" __slots__ = _element , _next def __init__(self, element, next): # carrega nó self._element = element # referência para elemento do usuário self._next = next # referência para o próximo nó def __init__ (self): """Cria fila vazia.""" self._tail = None self._size = 0 def __len__ (self): """Retorna o número de elementos na fila.""" return self._size def is_empty(self): """Retorna True se a fila está vazia.""" return self._size == 0 João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 22 / 33 EI12 - Lista Encadeada Circular Fila Circular como lista encadeada 2/3 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 def first(self): """Retorna (mas não remove) o elemento da frente da fila.""" if self.is_empty( ): raise Empty(Fila Vazia) head = self._tail._next return head._element def dequeue(self): """Remove e retorna o elemento do frente da fila. Levanta exceção Empty se fila está vazia.. """ if self.is_empty( ): raise Empty(Fila Vazia) oldhead = self._tail._next if self._size == 1: # remove único elemento self._tail = None # fila fica vazia else: self._tail._next = oldhead._next # bypass antigo head self._size -= 1 return oldhead._element João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 23 / 33 EI12 - Lista Encadeada Circular Fila Circular como lista encadeada 3/3 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 def enqueue(self, e): """Adiciona elemento ao fim da fila.""" newest = self._Node(e, None) # nó será o novo tail if self.is_empty( ): newest._next = newest # circular else: newest._next = self._tail._next # novo nó aponta para head self._tail._next = newest # antigo tail aponta para novo nó self._tail = newest # novo nó se torna tail self._size += 1 def rotate(self): """Roda elemento frontal para fim da fila.""" if self._size > 0: self._tail = self._tail._next # antigo head vira novo tail João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 24 / 33 EI12 - Lista Duplamente Encadeada Lista duplamente encadeada Numa lista duplamente encadeada cada nó mantém uma referência para o nó imediatamente anterior e outra para o nó imediatamente posterior. (no exemplo abaixo, usando sentinelas) João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 25 / 33 EI12 - Lista Duplamente Encadeada Por que usar sentinelas? Poderíamos implementar a lista duplamente encadeada sem sentinelas, mas elas simplicam enormemente a inserção e eliminação de nós, pois sempre existe um nó antes e depois e não precisamos tratar casos especiais, como anteriormente João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 26 / 33 EI12 - Lista Duplamente Encadeada Inserindo elemento João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 27 / 33 EI12 - Lista Duplamente Encadeada Inserindo elemento no início João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 28 / 33 EI12 - Lista Duplamente Encadeada Removendo elemento João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 29 / 33 EI12 - Lista Duplamente Encadeada Nó para lista duplamente encadeada 1 2 3 4 5 6 7 8 class _Node: """Classe não pública para armazenar um nó.""" __slots__ = _element , _prev , _next def __init__ (self, element, prev, next): self._element = element self._prev = prev self._next = next João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 30 / 33 EI12 - Lista Duplamente Encadeada lista duplamente encadeada 1/2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # coding=UTF-8 class _DoublyLinkedBase: """Uma classe base para lista duplamente encadeada.""" class _Node: """Classe não pública para armazenar um nó.""" __slots__ = _element , _prev , _next def __init__ (self, element, prev, next): self._element = element self._prev = prev self._next = next def __init__(self): """Cria lista vazia""" self._header = self._Node(None, None, None) self._trailer = self._Node(None, None, None) self._header._next = self._trailer # trailer após header self._trailer._prev = self._header # header antes de trailer self._size = 0 def __len__ (self): """Retorna o número de elementos na lista.""" João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 31 / 33 EI12 - Lista Duplamente Encadeada Lista duplamente encadeada 2/2 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 def is_empty(self): """Retorna True se a fila está vazia.""" return self._size == 0 def _insert_between(self, e, predecessor, successor): """Adiciona elemento e entre dois nós existentes e retorna novo nó." newest = self._Node(e, predecessor, successor) predecessor._next = newest successor._prev = newest self._size += 1 return newest def _delete_node(self, node): """Deleta nó não sentinela e retorna seu elemento.""" predecessor = node._prev successor = node._next predecessor._next = successor successor._prev = predecessor self._size -= 1 element = node._element node._prev = node._next = node._element = None João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 32 / 33 EI12 - Lista Duplamente Encadeada FIM João Araujo Ribeiro (UERJ) Estruturas de Informação I EstrInf 33 / 33