package TDALista; import java.util.Iterator; import java.util.NoSuchElementException; import javax.swing.text.Document; import javax.swing.text.ElementIterator; import java.util.Iterator; public class DoubleLinkedListSinCentinelas implements PositionList{ /** * * NodoD nos sirve para trabajar la lista como una lista de nodos * que implementan position * @author Lucas * */ private class NodoD implements Position { private E element; private NodoD prev; private NodoD next; public NodoD (NodoD a, NodoD s, E e) { element = e; prev = a; next = s; } public E element() { return element; } public NodoD getPrev() { return prev; } public NodoD getNext() { return next; } public void setElement(E e) { element = e; } public void setNext(NodoD n) { next = n; } public void setPrev(NodoD n) { prev = n; } public String toString() { return element.toString(); } } /** * Retorna el iterator de la lista * @author Lucas * * @param */ private class ElementIterator implements Iterator { protected PositionList lista; protected Position cursor; public ElementIterator (PositionList L) { lista = L; if (lista.isEmpty()) {cursor = null;} else {try { cursor = lista.first(); } catch (EmptyListException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public boolean hasNext() { return cursor != null; } public E next() throws NoSuchElementException { if (!hasNext()) {throw new NoSuchElementException ("Error: No hay siguiente");} E toReturn = cursor.element(); try { cursor = (cursor == lista.last()) ? null : lista.next(cursor); } catch (EmptyListException | InvalidPositionException | BoundaryViolationException e) { // TODO Auto-generated catch block e.printStackTrace(); } return toReturn; } } protected NodoD head; protected NodoD tail; protected int size; /** * Crea una nueva lista la cual inicializa con un nodo nulo para cabeza y cola, y tamaño cero. * @author Lucas */ public DoubleLinkedListSinCentinelas() { head = tail = new NodoD (null, null, null); size = 0; } /** * Consulta la cantidad de elementos de la lista. * @return int Cantidad de elementos de la lista. * @author Lucas */ public int size() { return size; } /** * Consulta si la lista esta vacia * @return Verdadero si la lista esta vacia, falso en caso contrario * @author Lucas */ public boolean isEmpty() { return size == 0; } /** * Devuelve la position del primer elemento de la lista, si la lista esta vacia arroja excepcion * @return Position, primer elemento de la lista. * @throws @link{EmptyListException} si la lista esta vacia. * @author Lucas */ public Position first() throws EmptyListException { if (isEmpty()) {throw new EmptyListException("La lista está vacía");} return head; } /** * Devuelve la position del ultimo elemento de la lista. * @return Position, ultimo elemento de la lista. * @throws @link{EmptyListException} si la lista esta vacia. * @author Lucas * */ public Position last() throws EmptyListException { if (isEmpty()) {throw new EmptyListException("La lista está vacía");} return tail; } /** * Este metodo privado nos sirve para validar la posicion que se pasa como parametro * controla que esta no sea nula, pertenezca a la lista y la lista no este vacia * @param Position p * @return NodoD la position a nodo * @throws @link{InvalidPositionException} si no cumple alguna de las dichas * @author Lucas */ private NodoD checkPosition(Position p) throws InvalidPositionException { try { if(size == 0) throw new InvalidPositionException("La lista esta vacia."); if(p == null) throw new InvalidPositionException("La posicion es nula."); if(p.element() == null) throw new InvalidPositionException("La posicion tiene un elemento nulo, i.e. fue invalidada anteriormente."); return (NodoD) p; } catch(ClassCastException e) { throw new InvalidPositionException("P no es un nodo de lista."); } } /** * Devuelve la posicion del elemento siguiente a la posicion pasada por parametro. * @param Position posicion a obtener su elemento siguiente. * @return Posicion del elemento siguiente a la posicion pasada por parametro. * @throws @link{InvalidPositionException} si el posicion pasada por parametro es invalida o la lista esta vacia. * @throws @link{BoundaryViolationException} si la posicion pasada por parametro corresponde al ultimo elemento de la lista. * @author Lucas */ public Position next(Position p) throws InvalidPositionException, BoundaryViolationException { NodoD d = checkPosition(p);//si el nodo es valido if (d == tail) {throw new BoundaryViolationException("Se cae de la lista");}// y no nos caemos de la lista return d.getNext();//retorna el siguiente } /** * Devuelve la posicion del elemento anterior a la posicion pasada por parametro. * @param Position a obtener su elemento anterior. * @return Posicion del elemento anterior a la posicion pasada por parametro. * @throws @link{InvalidPositionException} si la posicion pasada por parametro es invalida o la lista esta vacia. * @throws @link{BoundaryViolationException} si la posicion pasada por parametro corresponde al primer elemento de la lista. * @author Lucas */ public Position prev(Position p) throws InvalidPositionException, BoundaryViolationException { NodoD d = checkPosition(p); if (d == head) {throw new BoundaryViolationException("Se cae de la lista");} return d.getPrev(); } /** * Inserta un elemento al principio de la lista. * @param element Elemento a insertar al principio de la lista. * @author Lucas */ public void addFirst(E element) { if (size == 0) { // si el tamaño era 0, el nodo añadido se convierte en cabeza y cola a la vez head = tail = new NodoD (null, null, element); } else if (size == 1) {// si el tamaño era 1, el nodo añadido hace que tengamos que diferenciar de cabeza y cola head = new NodoD (null, tail, element); tail.setPrev(head); } else {// si el tamaño es mayor a 1, podemos agregar tranqui, solo preocupandonos por la cabeza NodoD aux = head; head = new NodoD (null, aux, element); aux.setPrev(head); } size++; } /** * Inserta un elemento al final de la lista. * @param element Elemento a insertar al final de la lista. * @author Lucas */ public void addLast(E element) { if (size == 0) {// si el tamaño era 0, el nodo añadido se convierte en cabeza y cola a la vez head = tail = new NodoD (null, null, element); } else if (size == 1) {// si el tamaño era 1, el nodo añadido hace que tengamos que diferenciar de cabeza y cola tail = new NodoD (head, null, element); head.setNext(tail); } else { NodoD aux = tail;// si el tamaño es mayor a 1, podemos agregar tranqui, solo preocupandonos por la cola tail = new NodoD (aux, null, element); aux.setNext(tail); } size++; } /** * Inserta un elemento luego de la positionn pasada por parametro. * @param p Position despues de la cual se insertara el elemento pasado por parametro. * @param element Elemento a insertar luego de la posicion pasada como parametro. * @throws @link{InvalidPositionException} si la posicion es invalida o la lista esta vacia. * @author Lucas */ public void addAfter(Position p, E element) throws InvalidPositionException { NodoD d = checkPosition(p);//valida que sea una posicion valida if (isEmpty()) {throw new InvalidPositionException("La lista esta vacia, no existe posicion.");} if (d == tail) {//si queremos añadir ultimo pasamos la responsabilidad a add last addLast(element); } else { NodoD nuevo = new NodoD (d, d.getNext(), element);// si no enlazamos entre medio de p y el siguiente de p if (d.getNext()!=null) d.getNext().setPrev(nuevo); d.setNext(nuevo); } size++; } /** * Inserta un elemento antes de la position pasada por parametro. * @param p Position antes de la cual se insertara el elemento pasado por parametro. * @param element Elemento a insertar luego de la posicion pasada como parametro. * @throws @link{InvalidPositionException} si la posicion es invalida o la lista esta vacia. * @author Lucas */ public void addBefore(Position p, E element) throws InvalidPositionException{ NodoD d = checkPosition(p);//valida que sea una posicion valida if (isEmpty()) {throw new InvalidPositionException("La lista esta vacia, no existe posicion.");} if (d == head) {//si el nodo es el primero, pasamos la responsabilidad a add first addFirst(element); } else { NodoD nuevo = new NodoD (d.getPrev(), d, element);// si no enlazamos entre medio de p y el anterior de p if (d.getPrev()!= null) d.getPrev().setNext(nuevo); d.setPrev(nuevo); } size++; } /** * Remueve el elemento que se encuentra en la position pasada por parametro. * @param Position p del elemento a eliminar. * @return element Elemento removido. * @throws @link{InvalidPositionException} si la posicition es invalida o la lista esta vacia. * @author Lucas */ public E remove(Position p) throws InvalidPositionException { NodoD d = checkPosition(p);//controla posicion valida if (isEmpty()) {throw new InvalidPositionException("No se puede eliminar nada, esta vacío");} NodoD anterior = d.getPrev(); NodoD posterior = d.getNext(); if (anterior != null) {anterior.setNext(posterior);}//enlaza el anterior con el posterior a p if (posterior != null) {posterior.setPrev(anterior);}//enlaza el posterior con el anterior a p if (size == 1) {//si elimino y habia un nodo, setea en null head = new NodoD(null,null,null); tail = head; } else if (size == 2) {//si elimino y habia dos nodos, ahora la cabeza y la cola seran el mismo nodo if(d == head) head = tail; else if (d == tail) tail = head; } else {//si habia mas de 2, controla que si eliminamos cabeza o cola, se vuelvana igualar al ultimo/primer nodo if (d == head) {head = posterior;} else if (d== tail) {tail = anterior;} } E aux = (E) d.element; d.setElement(null);// destruye el nodo d d.setNext(null); d.setPrev(null); size--; return aux; } /** * Establece el elemento en la position pasados por parametro. Reemplaza el elemento que se encontraba anteriormente en esa position y devuelve el elemento anterior. * @param Position p a establecer el elemento pasado por parametro. * @param element Elemento a establecer en la posici�n pasada por parametro. * @return Elemento anterior. * @throws @link{InvalidPositionException} si la posicion es invalida o la lista esta vacia. * @author Lucas */ public E set(Position p, E element) throws InvalidPositionException { NodoD d = checkPosition(p);//valida postion E aux = (E) d.element;//guarda el elemento d.setElement(element);//reemplaza return aux; } /** * Devuelve un iterador de todos los elementos de la lista. * @return Un iterador de todos los elementos de la lista. * @author Lucas */ public Iterator iterator() { return new ElementIterator(this); } /** * Devuelve una coleccion iterable de posiciones. * @return Una coleccion iterable de posiciones. * @author Lucas */ public Iterable> positions(){ PositionList> p = new DoubleLinkedListSinCentinelas>(); if(size != 0) { Position pos = head; while (pos!= tail) { p.addLast(pos); try { pos = next(pos); } catch (InvalidPositionException | BoundaryViolationException e) { //Esto no pasa porque controlamos el ultimo e.printStackTrace(); } } p.addLast(pos); } return p; } }