Listas Simplesmente Encadeadas Professores de Programação II Criando um objeto • Objeto é uma instância de uma classe; • Usamos o operador new para criar um objeto. Variável que conterá uma referência a um objeto ContaCorrente minhaConta; minhaConta = new ContaCorrente ( ); Criação do objeto ContaCorrente minhaConta = new ContaCorrente ( ); Programação II 2 Garbage Collection String str = “Primeiro espaço”; System.out.println (“Usando memória original: “+str); str = “Outro espaço”; System.out.println (“Usando outro espaço de memória: “+str); Primeiro espaço str Área de memória liberada pelo Garbage Collection 10 100 Outro espaço System.gc(); 10 100 Não obriga a limpar, mas “pede” para que o Garbage Collection limpe se possível Programação II 3 Listas: Tipo de Armazenamento • O tipo de armazenamento de uma lista linear pode ser classificado de acordo com a posição relativa na memória de dois nós consecutivos na lista (sempre contígua ou não). • Lista linear com alocação estática de memória – – – – Também chamadas de Listas Sequenciais Nós em posições contíguas de memória Geralmente representado por arrays Útil para implementar filas e pilhas (variáveis para controlar fim e início) • Lista linear com alocação dinâmica – Também chamadas de Listas Encadeadas – Posições de memória são alocadas a medida que são necessárias – Nós encontram-se aleatoriamente dispostos na memória e são interligados por ponteiros, que indicam a próxima posição da tabela • Nós precisam de um campo a mais: campo que indica o endereço do próximo nó. Programação II 4 Listas Simplesmente Encadeadas • Uma lista simplesmente encadeada é uma sequência de objetos alocados dinamicamente, onde cada objeto faz referência ao seu sucessor na lista • Lista encadeada básica: – possui variável head que referencia para o primeiro elemento da lista – cada Objeto refere a seu sucessor – ultimo elemento contém a referência null (para indicar que não referencia nenhum outro). Ineficiente: se queremos inserir um elemento no final da lista, temos que localizar o último elemento: para tanto é necessário percorrer todos os elementos da lista. Programação II 5 Lista Encadeada Básica element next head Apontador para o primeiro nó da lista Node ... null final de lista Programação II 6 Lista encadeada com referência ao último elemento da lista • Como tornar mais eficiente: – utilizar uma segunda variável, chamada tail, que referencia o último elemento da lista. – eficiência obtida a custa do espaço adicional head tail Apontador para o primeiro nó da lista Apontador para o último nó da lista ... null final de lista Programação II 7 Classe Node /** Nodo de uma lista simplesmente encadeada de strings **/ public class Node { private String element; //assumimos que os elementos são strings private Node next; /** Cria um nodo com um dado elemento e o próximo nodo **/ public Node(String s, Node n){ element = s; next = n; } /** Cria um nodo com um dado elemento e o próximo nodo em null**/ public Node( String element ) { this( element, null ); element next } /** Retorna o elemento deste nodo **/ public String getElement(){ return element; } /** Retorna o próximo elemento deste nodo **/ Node public Node getNext(){ return next; } /** Define o elemento deste nodo **/ public void setElement(String newElem){ element = newElem; } /** Define o próximo elemento deste nodo **/ public void setNext(Node newNext){ next = newNext; } } Programação II 8 Operações sobre lista – public boolean isEmpty() • verifica se a lista está vazia – public Node getFirst() • Retorna o primeiro elemento da lista, sem removê-lo – public Node getLast() • Retorna o último elemento da lista, sem removê-lo – public void addFirst( Node novoNodo ) • insere element na frente da lista – public void addLast( Node novoNodo ) • insere element no final da lista – public Node removeFirst() • remove e retorna o primeiro elemento da lista – public Node removeLast() • remove e retorna o primeiro elemento da lista – public void print() • exibe o conteúdo da lista Programação II 9 Class SLinkedList /** Lista simplesmente encadeada **/ public class SLinkedList { protected Node head; //nodo cabeça da lista protected Node tail; //nodo cauda da lista protected long size; //número de nodos da lista /** Construtor default que cria uma lista vazia **/ public SLinkedList(){ head = null; tail = null; size = 0; } //demais métodos aqui } Programação II 10 isEmpty(), getFirst() e getLast() public boolean isEmpty(){ return head == null; } public Node getFirst() throws UnderflowException { if (isEmpty()) throw new UnderflowException(); return head; } public Node getLast() throws UnderflowException { if (isEmpty()) throw new UnderflowException(); return tail; } Programação II 11 Inserção em lista simplesmente encadeada - Na cabeça da lista: tail head a ... tail head b ... tail head c ... Programação II 12 Inserção em lista simplesmente encadeada - Na cabeça da lista: public void addFirst(Node novoNodo){ novoNodo.setNext(head); head = novoNodo; size++; if(size == 1) tail = head; } Programação II 13 Inserção em lista simplesmente encadeada - Na cauda da lista: tail head a ... tail head b ... head c tail ... Programação II 14 Inserção em lista simplesmente encadeada - Na cauda da lista: public void addLast(Node novoNodo){ if(isEmpty()) addFirst(novoNodo); else{ novoNodo.setNext(null); tail.setNext(novoNodo); tail = novoNodo; size++; } } Programação II 15 Remoção em lista simplesmente encadeada - Da cabeça da lista: tail head a ... tail head b ... tail head c ... Programação II 16 Remoção em lista simplesmente encadeada - Da cabeça da lista: public Node removeFirst() throws UnderflowException { if(isEmpty()) throw new UnderflowException(); Node removedItem = head; if (head == tail) { head = tail = null; } else { head = head.getNext(); } return removedItem; } Programação II 17 Remoção em lista simplesmente encadeada - Da cauda da lista: tail head a ... current current current current head b tail ... current Programação II 18 Remoção em lista simplesmente encadeada - Da cauda da lista: public Node removeLast() throws UnderflowException { if (isEmpty()) throw new UnderflowException(); Node removedItem = tail; if (head == tail) { head = tail = null; } else { Node current = head; while (current.getNext() != tail) { current = current.getNext(); } tail = current; current.setNext(null); } return removedItem; } Programação II 19 Classe UnderflowException public class UnderflowException extends Exception { public String toString() { return "UNDERFLOW!"; } } Programação II 20 Exercício Como imprimir a lista simplesmente encadeada? a) Crie um método print(), que percorre a lista e imprime os elementos. Programação II 21 Exercício - Resposta public void print() { if (isEmpty()) { System.out.println("Empty list"); } else { System.out.print("The list is: "); Node current = head; while (current != null) { System.out.print(current.getElement().toString()+" "); current = current.getNext(); } Systemout.println("\n"); } } Programação II 22 Testando a Lista Simplesmente Encadeada public static void main(String args[]){ Node n = new Node (“A”); SLinkedList lista = new SLinkedList(); Lista.addFirst (n); try{ lista.addFirst(new Node("A")); lista.addFirst(new Node("B")); lista.addFirst(new Node("C")); lista.addLast(new Node("D")); lista.addLast(new Node("E")); lista.addLast(new Node("F")); lista.removeFirst(); lista.removeLast(); }catch(UnderflowException e){ System.out.println("ERRO: impossível remover!"); e.printStackTrace(); } lista.print(); } Programação II 23 Exercício Como inserir um elemento no meio de uma lista simplesmente encadeada? a) Crie um método chamado addAfter(Node n, int pos), que insere o nodo n depois do nodo de número pos (considerando que o primeiro nodo é o nodo na posição 0). b) Crie um método chamado addBefore(Node n, int pos), que insere o nodo n antes do nodo de número pos (considerando que o primeiro nodo é o nodo na posição 0). Programação II 24 Exercício Como fazer a lista ficar genérica? a) Transforme a classe Node (que utiliza String) para um tipo genérico E b) Transforme a classe SLinkedList para um tipo genérico E (o mesmo do Node) - Programação II 25 Classe Node com String /** Nodo de uma lista simplesmente encadeada de strings **/ public class Node { private String element; //assumimos que os elementos são strings private Node next; /** Cria um nodo com um dado elemento e o próximo nodo **/ public Node(String s, Node n){ element = s; next = n; } /** Cria um nodo com um dado elemento e o próximo nodo em null**/ public Node( String element ) { this( element, null ); } /** Retorna o elemento deste nodo **/ public String getElement(){ return element; } /** Retorna o próximo elemento deste nodo **/ public Node getNext(){ return next; } /** Define o elemento deste nodo **/ public void setElement(String newElem){ element = newElem; } /** Define o próximo elemento deste nodo **/ public void setNext(Node newNext){ next = newNext; } } Programação II 26 Classe Node Genérica /** Nodo de uma lista simplesmente encadeada de strings **/ public class Node<E>{ private E element; private Node<E> next; /** Cria um nodo com um dado elemento e o próximo nodo **/ public Node(E s, Node<E> n){ element = s; next = n; } /** Cria um nodo com um dado elemento e o próximo nodo em null**/ public Node( E element ) { this( element, null ); } /** Retorna o elemento deste nodo **/ public E getElement(){ return element; } /** Retorna o próximo elemento deste nodo **/ public Node<E> getNext(){ return next; } /** Define o elemento deste nodo **/ public void setElement(E newElem){ element = newElem; } /** Define o próximo elemento deste nodo **/ public void setNext(Node<E> newNext){ next = newNext; } } Programação II 27 Classe SLinkedList Genérica /** Lista simplesmente encadeada **/ public class SLinkedList<E> { protected Node<E> head; //nodo cabeça da lista protected Node<E> tail; //nodo cauda da lista protected long size; //número de nodos da lista /** Construtor default que cria uma lista vazia **/ public SLinkedList(){ head = null; tail = null; size = 0; } //demais métodos aqui //todas as ocorrências do tipo Node devem ser alteradas para Node<E> } Programação II 28 Testando a Lista Simplesmente Encadeada Genérica public static void main(String args[]){ SLinkedList<String> lista = new SLinkedList<String>(); try{ lista.addFirst(new Node<String>("A")); lista.addFirst(new Node<String>("B")); lista.addFirst(new Node<String>("C")); lista.addLast(new Node<String>("D")); lista.addLast(new Node<String>("E")); lista.addLast(new Node<String>("F")); //lista.addLast(new Node<Integer>(1)); lista.removeFirst(); lista.removeLast(); lista.addAfter(new Node<String>("0"),3); lista.addBefore(new Node<String>("1"),4); lista.addBefore(new Node<String>("3"), 8); }catch(IndexOutOfBoundsException e){ System.out.println("ERRO: índice iválido!"); e.printStackTrace(); }catch(UnderflowException e){ System.out.println("ERRO: lista vazia, impossível remover!"); e.printStackTrace(); } lista.print(); } Prof. Mateus Raeder - Programação II 29