TADs Vector, Lista e Sequência ATAI
TAD Vector TAD Vector suporta os seguintes métodos principais: Uma sequencia S de n elementos Rank (posição) do elemento e da sequencia S indica o número de elementos antes de e em S. TAD Vector suporta os seguintes métodos principais: elemAtRank (r): retorna o elemento da S que esta na posição r. Erro : se r < 0 ou r > n-1, onde n é o numero actual de elementos. Entrada: int; Saída: Objecto replaceAtRank (r, e): Substitui o elemento na posição r com e e retorna o objecto substituído. Erro : se r < 0 ou r > n-1, onde n é o numero actual de elementos Entrada: int r e Objecto e; Saída: Objecto insertAtRank (r, e): Insere um novo elemento e na posição r. Erro : se r < 0 ou r > n-1, onde n é o numero de elementos antes da inserção Entrada: int r e Objecto e; Saída: Nenhuma removeAtRank (r): Remove da sequencia S o elemento que esta na posição r. Entrada: int r; Saída: Objecto
Exemplo de execução Operação Output S insertAtRank(0,7) - (7) (4, 7) elemAtRank(1) 7 insertAtRank(2,2) (4, 7, 2) elemAtRank(3) error removeAtRank(1) (4, 2) insertAtRank(1,5) (4, 5, 2) insertAtRank(1,3) (4, 3, 5, 2) insertAtRank(4,9) (4, 3, 5, 2, 9) elemAtRank(2) 5
Implementação do Deque com TAD Vector Métodos Deque Métodos do Vector tamanho() size() estaVazia() isEmpty() primeiro() elemAtRank(0) ultimo() elemAtRank(size()-1) inserirPrimeiro(e) insertAtRank(0,e) inserirUltimo(e) insertAtRank(size(),e) removePrimeiro() removeAtRank(0) removerUltimo() removeAtRank(size()-1)
Implementação estática do TAD Vector Pseudo-Codigo: Algoritmo insertAtRank(r,e): for i = n - 1, n - 2, ... , r do S[i+1] s[i] S[r] e n n + 1 Algoritmo removeAtRank(r): e S[r] for i = r, r + 1, ... , n - 2 do S[i] S[i + 1] n n - 1 return
Implementação do TAD Vector com classe Vector da Java Métodos do TAD Vector Métodos da classe Vector (java.util.Vector) size() isEmpty() elemAtRank(r) get(r) replaceAtRank(r,e) set(r,e) insertAtRank(r,e) add(r,e) removeAtRank(r) remove(r)
Implementação dinâmica do TAD Vector (lista duplamente ligada) – inserir elemento Criar novo nó: Lista antes da inserção: Lista depois da inserção:
Implementação dinâmica do TAD Vector (lista duplamente ligada) – inserir elemento public void insertAtRank (int rank, Object element) throws BoundaryViolationException { if (rank < 0 || rank > size()) throw new BoundaryViolationException(“invalid rank”); DLNode next = nodeAtRank(rank); // the new node //will be right before this DLNode prev = next.getPrev(); // the new node //will be right after this DLNode node = new DLNode(element, prev, next); // new node knows about its next & prev. Now // we tell next & prev about the new node. next.setPrev(node); prev.setNext(node); size++; }
Implementação dinâmica do TAD Vector (lista duplamente ligada) – apagar elemento Lista antes da operação: Apagar nó: Lista depois da operação:
Implementação dinâmica do TAD Vector (lista duplamente ligada) – apagar elemento public Object removeAtRank (int rank) throws BoundaryViolationException { if (rank < 0 || rank > size()-1) throw new BoundaryViolationException(“Invalid rank.”); DLNode node = nodeAtRank(rank); // node to be removed DLNode next = node.getNext(); // node before it DLNode prev = node.getPrev(); // node after it prev.setNext(next); next.setPrev(prev); size--; return node.getElement(); // returns the element of the // deleted node }
Implementação dinâmica do TAD Vector (lista duplamente ligada) – procura de elemento numa posição private DLNode nodeAtRank (int rank) { // auxiliary method to find the node of the // element with the given rank DLNode node; if (rank <= size()/2) { //scan forward from head node = header.getNext(); for (int i=0; i < rank; i++) node = node.getNext(); }else { // scan backward from the tail node = trailer.getPrev(); for (int i=0; i < size()-rank-1 ; i++) node = node.getPrev(); } return node;
Passagem de nó para o elemento corrente Noção de elemento corrente (current position) Noção intuitiva de “ lugar” de um elemento Elemento corrente é definido de um modo relativo (relação antes/depois) Elemento corrente é um TAD Position que só possui um método: element(): Retorna o elemento corrente Position é uma abstracção Na implementação dinâmica: Position é a referência para um nó, logo element() retorna o Objecto armazenado no nó. Na implementação estática: Position é o indice do array, logo element() retorna o Objecto armazenado no array no indice indicado.
TAD Lista TAD Lista - TAD sequencia baseado na noção de elemento corrente Métodos genéricos: size(), isEmpty() Métodos selectores: isFirst(p), isLast(p) Entrada: Position p; Saída: Boolean first(), last() Entrada: nenhuma; Saída: Position before(p), after(p) Entrada: Position p; Saída: Position Métodos modificadores: swapElements(p,q) Entrada: Position p e Position q ; Saída: nenhuma replaceElement(p,e) Entrada: Position p e Object e ; Saída: Object (que estava na posição p) insertFirst(e), insertLast(e) insertBefore(p,e), insertAfter(p,e) remove(p) Cada método é implementadoe em O(1), se utilizar uma estrutura dinâmica representada pela lista duplamente ligada.
Interface List public interface List { public int size(); public boolean isEmpty(); public boolean isFirst (Position p) throws InvalidPositionException; public boolean isLast (Position p) throws InvalidPositionException; public Position first() throws EmptyContainerException; public Position last() throws EmptyContainerException; public Position before (Position p) throws InvalidPositionException, BoundaryViolationException; public Position after (Position p) public Position insertBefore (Position p, Object element) throws InvalidPositionException; public Position insertAfter (Position p, Object element) public Position insertFirst (Object element); public Position insertLast (Object element); public Object remove (Position p) throws InvalidPositionException; public Object replaceElement (Position p, Object element) public void swapElements (Position a, Position b) }
Interface Position Interface Position { public Object element() throws InvalidPositionException }
Classe DNode class DNode implements Position { private DNode prev, next;// References to the nodes before and after private Object element; // Element stored in this position // Constructor public DNode (DNode newPrev, DNode newNext, Object elem) { prev = newPrev; next = newNext; element = elem; } // Method from interface Position public Object element() throws InvalidPositionException { if ((prev == null) && (next == null)) throw new InvalidPositionException("Position is not in a list!"); return element; // Accessor methods public DNode getNext() { return next; } public DNode getPrev() { return prev; } // Update methods public void setNext (DNode newNext) { next = newNext; } public void setPrev (DNode newPrev) { prev = newPrev; } public void setElement (Object newElement) { element = newElement; }
Implementação dinâmica (lista duplamente ligada) do TAD Lista public class NodeList implements List { protected int numElts; // Number of items in the list protected DNode header, trailer; // Special sentinels // Constructor; O(1) time public NodeList() { numElts = 0; header = new DNode(null, null, null); // create header trailer = new DNode(header, null, null); // create trailer header.setNext(trailer); // make header and trailer point to each other } // Simple accessor methods: public int size() { return numElts; } // O(1) time public boolean isEmpty() { return (numElts < 1); } // O(1) time public boolean isFirst (Position p) // O(1) time throws InvalidPositionException { DNode v = checkPosition(p); return v.getPrev() == header;
Implementação dinâmica (lista duplamente ligada) do TAD Lista // Convenience function; O(1) time protected DNode checkPosition(Position p) throws InvalidPositionException { if (p == null) throw new InvalidPositionException ("Null Position passed to NodeList."); if (p == header) ("The header node is not a valid position"); if (p == trailer) ("The trailer node is not a valid position"); try { DNode temp = (DNode)p; if ((temp.getPrev() == null) || (temp.getNext() == null)) ("Position does not belong to a valid NodeList"); return temp; } catch (ClassCastException e) { ("Position is of wrong type for this container."); }
Implementação dinâmica (lista duplamente ligada) do TAD Lista public Position first() // O(1) time throws EmptyContainerException { if (isEmpty()) throw new EmptyContainerException("List is empty"); return header.getNext(); } public Position before (Position p) // O(1) time throws InvalidPositionException, BoundaryViolationException { DNode v = checkPosition(p); DNode prev = v.getPrev(); if (prev == header) throw new BoundaryViolationException ("Cannot advance past the beginning of the list"); return prev;
Implementação dinâmica (lista duplamente ligada) do TAD Lista public Position insertBefore (Position p, Object element) throws InvalidPositionException {// O(1) time DNode v = checkPosition(p); numElts++; DNode newNode = new DNode(v.getPrev(), v, element); v.getPrev().setNext(newNode); v.setPrev(newNode); return newNode; } public Position insertFirst (Object element) {// O(1) time DNode newNode = new DNode(header, header.getNext(), element); header.getNext().setPrev(newNode); header.setNext(newNode);
Implementação dinâmica (lista duplamente ligada) do TAD Lista public Object remove (Position p) // O(1) time throws InvalidPositionException { DNode v = checkPosition(p); numElts--; DNode vPrev = v.getPrev(); DNode vNext = v.getNext(); vPrev.setNext(vNext); vNext.setPrev(vPrev); Object vElem = v.element(); // unlink the position from the list and make it invalid v.setNext(null); v.setPrev(null); return vElem; }
Implementação dinâmica (lista duplamente ligada) do TAD Lista public Object replaceElement (Position p, Object element) throws InvalidPositionException { // O(1) time DNode v = checkPosition(p); Object oldElt = v.element(); v.setElement(element); return oldElt; } public void swapElements (Position a, Position b) DNode pA = checkPosition(a); DNode pB = checkPosition(b); Object temp = pA.element(); pA.setElement(pB.element()); pB.setElement(temp);
TAD Sequencia Combinação do TAD Vector e TAD Lista (herança multipla de interfaces) Adiciona métodos que fazem a ponte entre posição (int) e elemento corrente -atRank(r) posiciona elemento corrente -rankOf(p) retorna a posição do elemento p
Interface Sequencia interface Sequence extends List, Vector { // Additional "bridging" methods: public Position atRank (int rank) throws BoundaryViolationException; public int rankOf (Position position) throws InvalidPositionException; }
Comparação da implementação do TAD Sequencia
Implementação dinâmica (lista duplamente ligada) do TAD Sequencia public class NodeSequence extends NodeList implements Sequence { // Check that rank is in the range [0,numElts-1]; O(1) time protected void checkRank (int rank) throws BoundaryViolationException { if (rank < 0 || rank >= numElts) throw new BoundaryViolationException("Rank " + rank + " is invalid for this sequence of " + numElts + " elements."); } public Position atRank (int rank) { DNode node; checkRank(rank); if (rank <= size()/2) { // scan forward from the head node = header.getNext(); for (int i=0; i < rank; i++) node = node.getNext(); else { // scan backward from the tail node = trailer.getPrev(); for (int i=1; i < size()-rank; i++) node = node.getPrev(); return node;
Implementação dinâmica (lista duplamente ligada) do TAD Sequencia // . . . (skipping methods elemAtRank(r) and rankOf(p)) public void insertAtRank (int rank, Object element) throws BoundaryViolationException { // O(n) time if (rank == size()) // we shouldn't checkRank in this case insertLast(element); else { checkRank(rank); insertBefore(atRank(rank), element); } public Object removeAtRank (int rank) // O(n) time throws BoundaryViolationException { return remove(atRank(rank)); public Object replaceAtRank (int rank, Object element) return replaceElement(atRank(rank),element);