Hola a todos, hoy os explicare que son y como programar la estructura de una lista enlazada en Java.
Una lista dinámica es una colección de objetos enlazadas entre si. Es lo que se denomina una estructura dinámica, estas pueden crecer tanto como se quiera.
No se deben confundir con los arrays, estos debemos definirles el tamaño que tendrán al crearlos.
Estas listas esta compuesta por una clase que maneja la lista y otra que contiene la información de los objetos de la lista, llamados nodos.
/** * * @author DiscoDurodeRoer * @param <T> */ public class Nodo<T> { private T dato; private Nodo<T> siguiente; /** * Constructor por defecto */ public Nodo(){ siguiente=null; } /** * Le pasamos un dato al nodo * @param p */ public Nodo(T p){ siguiente=null; dato = p; } /** * Le pasamos un dato y su siguiente nodo al nodo * @param t Dato a insertar * @param siguiente Su sisguiente nodo */ public Nodo(T t, Nodo<T> siguiente){ this.siguiente=siguiente; dato = t; } public T getDato() { return dato; } public void setDato(T dato) { this.dato = dato; } public Nodo<T> getSiguiente() { return siguiente; } public void setSiguiente(Nodo<T> siguiente) { this.siguiente = siguiente; } }
package ejercicio_ed_8_discoduroderoer; import java.util.Iterator; /** * Lista Dinamica Version 2.0 * * @author DiscoDurodeRoer * @param <T> */ public class ListaDinamica<T> implements Iterable<T>{ //Atributos private Nodo<T> primero; private Nodo<T> ultimo; private int tamanio; public ListaDinamica() { primero = null; ultimo = null; tamanio = 0; } /** * Indica si esta la lista vacia o no * * @return */ public boolean isEmpty() { return tamanio == 0; } /** * Devuelve el tamaño de la lista * * @return */ public int size() { return tamanio; } /** * Devuelve el elemento en la posicion indicada * * @param index * @return */ public T get(int index) { //si esta vacio o el indice no es correcto, devuelve null if (isEmpty() || (index < 0 || index >= size())) { return null; } else if (index == 0) { return getFirst(); //Cojo el primero } else if (index == size() - 1) { return getLast(); //Cojo el ultimo } else { //Uso la funcion getNode para coger el nodo deseado Nodo<T> buscado = getNode(index); return buscado.getDato(); } } /** * Devuelve el primer elemento, null si esta vacia la lista * * @return */ public T getFirst() { //Si esta vacia, no hay primero que coger if (isEmpty()) { return null; } else { return primero.getDato(); } } /** * Devuelve el ultimo elemento, null si esta vacia la lista * * @return */ public T getLast() { //Si esta vacia, no hay ultimo que coger if (isEmpty()) { return null; } else { return ultimo.getDato(); } } /** * Devuelve el nodo completo de una posicion concreta * * @param index * @return */ private Nodo<T> getNode(int index) { //si esta vacio o el indice no es correcto, devuelve null if (isEmpty() || (index < 0 || index >= size())) { return null; } else if (index == 0) { return primero; //devuelvo el primero } else if (index == size() - 1) { return ultimo; //devuelvo el ultimo } else { Nodo<T> buscado = primero; //Busco el nodo deseado con un recorrido int contador = 0; while (contador < index) { contador++; buscado = buscado.getSiguiente(); } //Me devuelve el buscado return buscado; } } /** * Añade un elemento al final de la lista * * @param elemento * @return elemento añadido */ public T addLast(T elemento) { Nodo<T> aux; //Si esta vacia, hago lo mismo que si fuera añadir el primero if (isEmpty()) { return addFirst(elemento); } else { //Hago el intercambio aux = new Nodo<>(elemento, null); ultimo.setSiguiente(aux); ultimo = aux; } //Aumento el tamanño tamanio++; return ultimo.getDato(); } /** * Añade el elemento al principio de la lista * * @param elemento * @return elemento añadido */ public T addFirst(T elemento) { Nodo<T> aux; //si esta vacia, el nodo será el primero y ultimo if (isEmpty()) { aux = new Nodo<>(elemento, null); primero = aux; ultimo = aux; } else { //Hago el intercambio Nodo<T> primeroActual = primero; aux = new Nodo<>(elemento, primeroActual); primero = aux; } //Aumento el tamanño tamanio++; return primero.getDato(); } /** * Añade un elemento en una posicion indicada * * @param elemento * @param index debe ser un indice valido * @return elemento añadido */ public T add(T elemento, int index) { //si esta vacio o el indice no es correcto, devuelve null if (index == 0) { return addFirst(elemento); //Añade en la primera posicion } else if (index == size()) { return addLast(elemento); //añade en la ultima posicion } else if ((index < 0 || index >= size())) { return null; } else { //Cojo el anterior nodo al que estoy buscando Nodo<T> buscado_anterior = getNode(index - 1); //Cojo el nodo de la posicion indicada Nodo<T> buscado_actual = getNode(index); //Creo el nuevo novo, este apuntara al de la posicion actual Nodo<T> aux = new Nodo<>(elemento, buscado_actual); //el nodo anterior apunta a nuestro nuevo nodo buscado_anterior.setSiguiente(aux); //Aumento el tamaño tamanio++; return getNode(index).getDato(); } } /** * Devuelve el estado de la lista * * @return */ public String toString() { String contenido = ""; //Si esta vacia, lo indica if (isEmpty()) { contenido = "Lista vacia"; } else { Nodo<T> aux = primero; //Recorre la lista, mostrando el contenido while (aux != null) { contenido += aux.toString(); aux = aux.getSiguiente(); } } return contenido; } /** * Indica si existe el elemento indicado * * @param elemento * @return */ public boolean exists(T elemento) { //Si esta vacio, devuelve el false if (isEmpty()) { return false; } else { Nodo<T> aux = primero; //Recorremos la lista while (aux != null) { if (elemento.equals(aux.getDato())) { //Mejor .equals que == return true; //Existe } aux = aux.getSiguiente(); } //Si no lo encuentra devuelve false return false; } } /** * Indica la posición del elemento * * @param elemento * @return */ public int indexOf(T elemento) { //Si esta vacio, devuelvemos -1 if (isEmpty()) { return -1; } else { Nodo<T> aux = primero; int posicion = 0; while (aux != null) { if (elemento.equals(aux.getDato())) { //Mejor .equals que == return posicion; //Existe } posicion++; aux = aux.getSiguiente(); } //Si no lo encuentra devuelve -1 return -1; } } /** * Elimina el primer elemento de la lista * * @return */ public T removeFirst() { //Si la lista esta vacia, devolvemos null if (isEmpty()) { return null; } else { //Guardo el elemento antes T elemento = primero.getDato(); //Cojo el segundo Nodo<T> aux = primero.getSiguiente(); primero = null; //Lo marco como null para el recolector primero = aux; //Este es mi nuevo primero //En caso de que borremos el ultimo elemento,el ultimo también if (size() == 1) { ultimo = null; } tamanio--; return elemento; } } /** * Borra el ultimo elemento de la lista * * @return */ public T removeLast() { if (isEmpty()) { return null; } else { //Coge el elemento antes de borrar T elemento = ultimo.getDato(); //Cojo el penultimo Nodo<T> aux = getNode(size() - 2); //En caso de que sea null //Hay 1 o dos elementos if (aux == null) { //marco el ultimo como nulo ultimo = null; //Si hay dos, el primero y el ultimo seran el mismo //Si hay 1 elemento, significa que borramos la lista if (size() == 2) { ultimo = primero; } else { primero = null; } } else { //el penultimo es el nuevo ultimo //y le ponemos como siguiente nulo ultimo = null; ultimo = aux; ultimo.setSiguiente(null); } tamanio--; return elemento; } } /** * Elimina el nodo de la lista en una posicion concreta * * @param index * @return */ public T remove(int index) { //si esta vacio o el indice no es correcto, devuelve null if (isEmpty() || (index < 0 || index >= size())) { return null; } else if (index == 0) { return removeFirst(); } else if (index == size() - 1) { return removeLast(); } else { //Cojo el nodo anterior al que quiero borrar Nodo<T> nodo_anterior = getNode(index - 1); //Cojo el nodo que quiero borrar Nodo<T> nodo_actual = getNode(index); //Cojo el elemento antes de borrar T elemento = nodo_actual.getDato(); //Cojo el nodo siguiente al que quiero borrar Nodo<T> nodo_siguiente = nodo_actual.getSiguiente(); //Lo marco para borrar para el recolector nodo_actual = null; //El nodo anterior apunta al nodo siguiente nodo_anterior.setSiguiente(nodo_siguiente); tamanio--; return elemento; } } /** * Modifico el elemento de una posicion No afecta a la estructura de la * lista * * @param elemento * @param index * @return */ public T modify(T elemento, int index) { //si esta vacio o el indice no es correcto, devuelve null if (isEmpty() || (index < 0 || index >= size())) { return null; } else { //Nodo actual Nodo<T> aux = getNode(index); //modifico aux.setElemento(elemento); return aux.getDato(); } } @Override public Iterator<T> iterator() { return new MyIterator(); } //Creo la clase interna MyIterator, que implementa la interfaz Iterator private class MyIterator<ListaDinamica> implements Iterator<T>{ //Indica el siguiente elemento que se va a devolver private int siguiente; //Indica si hay un elemento @Override public boolean hasNext() { return getNode(siguiente)!=null; } //Devuelve el elemento actual e incrementa al siguiente @Override public T next() { T elemento = getNode(siguiente).getDato(); siguiente++; return elemento; } } }
Os dejo también un pequeño fichero de prueba para que veáis como funciona.
package ejercicio_ed_8_discoduroderoer; import java.util.Iterator; public class Ejercicio_ED_8_Discoduroderoer { public static void main(String[] args) { //Version 1.0 ListaDinamica<Integer> lista = new ListaDinamica<>(); //Añadimos elementos, recordar que devuelve el elemento System.out.println("Añadido el elemento "+lista.addLast(1)); System.out.println("Añadido el elemento "+lista.addLast(2)); System.out.println("Añadido el elemento "+lista.addLast(3)); System.out.println("Añadido el elemento "+lista.addFirst(4)); System.out.println("Añadido el elemento "+lista.addLast(5)); System.out.println("Añadido el elemento "+lista.addLast(6)); System.out.println("Añadido el elemento "+lista.add(7, 2)); System.out.println("Añadido el elemento "+lista.add(8, 4)); System.out.println("Añadido el elemento "+lista.addFirst(9)); //Orden actual: 9 4 1 7 2 8 3 5 6 System.out.println(""); System.out.println("Estado de la lista"); System.out.println(lista.toString()); //Cojo el valor de la posicion 7 = 5 System.out.println("Elemento de la posicion 7: "+lista.get(7)); //Cojo el valor de la posicion 9 = null, ya que no existe esa posición System.out.println("Elemento de la posicion 9: "+lista.get(9)); //Cojo el valor de la primera posicion = 9 System.out.println("Elemento de la primera posicion: "+lista.getFirst()); //Cojo el valor de la ultima posicion = 6 System.out.println("Elemento de la ultima posicion: "+lista.getLast()); //Version 2.0 System.out.println("Borrado el primer elemento "+lista.removeFirst()); System.out.println("Borrado el elemento de la tercera posicion "+lista.remove(2)); System.out.println("Borrado el primer elemento "+lista.removeFirst()); System.out.println("Borrado el elemento de la sexta posicion "+lista.remove(5)); System.out.println("Borrado el elemento "+lista.removeLast()); //orden actual: 1 2 8 3 System.out.println(""); System.out.println("Estado de la lista"); System.out.println(lista.toString()); //true System.out.println("¿Existe el elemento 2? "+lista.exists(2)); //false System.out.println("¿Existe el elemento 2? "+lista.exists(10)); //Posicion 1 System.out.println("Posicion del elemento 2: "+lista.indexOf(2)); //Posicicon -1, no existe System.out.println("Posicion del elemento 10: "+lista.indexOf(10)); //Elemento modificado lista.modify(10, 0); //orden actual: 10 2 8 3 System.out.println(""); System.out.println("Estado de la lista"); System.out.println(lista.toString()); System.out.println("Iterable clasico"); Iterator<Integer> it = lista.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("Iterable for each"); for(int i:lista){ System.out.println(i); } } }
Como vemos, el único atributo de la lista es primero que es el primer elemento, es decir, su referencia, este con su atributo siguiente apuntara al siguiente elemento cuando se añade un nuevo elemento. Puede tener también otros atributos, como ultimo que indicara el ultimo elemento.
Esta lista dinámica puede usarse para cualquier tipo de dato, gracias a los genéricos, fíjate en el fichero de prueba de como se debe iniciar. Una vez hecho, todos los datos son de ese tipo dentro de un nodo
Veamos un pequeño esquema sobre como es una lista enlazada.
Cuando la creamos tendría este aspecto.
Como vemos, no tiene nada, ya que no hemos insertado nada. Cuando insertamos un dato, internamente se crea un nodo, si la lista esta vacía sera el primero, sino lo esta, normalmente, va al final pero según como quieras insertar.
Insertamos otro elemento al final.
Cuando insertamos datos (en este caso 2 elementos), primero apunta al primer nodo y este al segundo. En el último nodo, el atributo siguiente es null, ya que no hay mas nodos.
También podemos borrar, si borramos el primero, el nodo2 sera el nuevo primero.
Y así consecutivamente, os recomiendo ejecutar el código de prueba e intentar comprender el código.
Para recorrer una lista enlazada que tenga varios nodos, siempre empezamos por el nodo primero y usando el método getSiguiente(), avanzamos por cada uno de los nodos. El código sería así:
Nodo<T> aux=primero; //aux apunta al primero while(aux!=null){ //Lo que quieras aux=aux.getSiguiente(); }
Gráficamente, se haría así para esta lista enlazada:
Aux apunta al primer nodo.
Después, aux apunta al segundo nodo.
Por ultimo, aux vale null pero como en la comprobación del while hemos puesto que si aux!=null continue, como es null, se para.
Os dejo una serie de vídeos donde hemos ido creándola.
Os dejo aquí el repositorio de Github.
Espero que os sea de ayuda. Si teneos dudas, preguntad. Estamos para ayudarte.
mil gracias por tu buen aporte
en relación a este apartado, teniendo la lista con números aleatorios
como puedo mostrar en que posición entra cada uno de los datos?
Gracias por la expliación, me ayudó bastante para mi clase de estructura de datos ^.^
gracias, estaba liado tratando de arreglar mi funcion nodo y lista
, ¿esto que es?
pregunta como agrego el fichero para que funcione porque me detecta muchos errores en donde dice nodo
excelente muchas gracias!! me sirvio mucho!!
No puedo descargar el archivo adjunto
Que tal,
No termino de entender a que te refieres con «Posicion del dato 5 desde la posicion 7: »
Podrias ayudarme a entender
Muy buen material gracias.