Universidad Los Ángeles de Chimbote Curso: Estructuras de datos LISTAS CIRCULARES Una lista circular es una lista lineal en la que el último elemento apunta al primero. Entonces es posible acceder a cualquier elemento de la lista desde cualquier punto dado. Las operaciones sobre una lista circular resultan más sencillas ya que se evitan casos especiales. Por ejemplo, el método añadir de la clase ClistaLinealSE expuesta anteriormente contempla dos casos: insertar al principio de la lista e insertar a continuación de un elemento. La siguiente figura muestra cómo se ve una lista circular simplemente enlazada. ultimo Cuando recorremos una lista circular, diremos que hemos llegado al final de la misma cuando nos encontremos de nuevo en el punto de partida, suponiendo, desde luego, que el punto de partida se guarda de alguna manera en la lista; por ejemplo con una referencia fija al mismo. Esta referencia puede ser al primer elemento de la lista, también puede ser al último elemento, en cuyo caso también es conocida la dirección del primer elemento. Otra posible solución sería poner un elemento especial identificable en cada lista circular como lugar de partida. Este elemento especial recibe el nombre de elemento de cabecera de la lista. Esto presenta, además, la ventaja de que la lista circular no estará nunca vacía. Como ejemplo, vamos a construir una lista circular con una referencia fija al último elemento es equivalente a una lista lineal recta con dos referencias, una al principio y otra al final. Para construir una lista circular, primero tendremos que definir la clase de objetos que van a formar parte de la misma. Por ejemplo, cada elemento de la lista puede definirse como una estructura de datos con dos miembros: una referencia al elemento siguiente y otra al área de datos . El área de datos puede ser de un tipo predefinido o de un tipo definido por el usuario. Según esto, el tipo de cada elemento de la lista puede venir definido de la siguiente forma: private class CElemento { // Atributos private Object datos; // referencia a los datos private CElemento siguiente; // siguiente elemento // Métodos private CElemento() {} // constructor Curso: Estructuras de datos Docente : Ing. Hèctor Fiestas Bancayàn Universidad Los Ángeles de Chimbote Curso: Estructuras de datos private CElemento(Object d, CElemento s) // constructor { datos = d; siguiente = s; } } Vemos que por tratarse de una lista lineal simplemente enlazada, aunque sea circular, la estructura de sus elementos no varía con respecto a lo estudiado anteriormente. Podemos automatizar el proceso de implementar una lista circular diseñando una clase CListaCircularSE (Clase Lista Circular Simplemente Enlazada) que proporcione los atributos y métodos necesarios para crear cada elemento de la lista, así como para permitir el acceso a los mismos. Esta clase nos permitirá posteriormente derivar otras clases que sean más específicas, por ejemplo, una clase para manipular pilas o una clase para manipular colas. Estas estructuras de datos las estudiaremos un poco más adelante. La clase CListaCircularSE La clase CListaCircularSE que vamos a implementar incluirá un atributo último que valdrá null cuando la lista esté vacía y cuando no, referenciará siempre a su último elemento; una clase interna, CELemento, que definirá la estructura de los elementos; y los métodos indicados en la tabla siguiente: Método tamaño Significado Devuelve el número de elementos de la lista. No tiene parámetros. añadirAlPrincipio Añade un elemento al principio (el primer elemento es el referenciado por ultimo.siguiente). Tiene un parámetro que es una referencia de tipo Object al objeto a añadir. No devuelve ningún valor. añadirAlFinal Añade un elemento al final (el último elemento siempre estará referenciado por ultimo). Tiene un parámetro que es una referencia de tipo Object al objeto a añadir. No devuelve ningún valor. borrar Borra el primer elemento (el primer elemento es el referenciado por ultimo.siguiente). No tiene parámetros. Devuelve una referencia al objeto borrado o null si la lista está vacía. obtener Devuelve el elemento de la posición i o bien null si la lista está vacía o el índice está fuera de los límites. Tiene un Curso: Estructuras de datos Docente : Ing. Hèctor Fiestas Bancayàn Universidad Los Ángeles de Chimbote Curso: Estructuras de datos parámetro correspondiente a la posición i del objeto que se desea obtener. A continuación se presenta el código correspondiente a la definición de la clase CListaCircularSE. ////////////////////////////////////////////////////////////////// // Lista lineal circular simplemente enlazada // public class CListaCircularSE { // último: referencia el último elemento. // último.siguiente referencia al primer elemento de la lista. private CElemento último = null; // Elemento de una lista lineal circular simplemente enlazada private class CElemento { // Atributos private Object datos; // referencia a los datos private CElemento siguiente; // siguiente elemento // Métodos private CElemento() {} // constructor private CElemento(Object d, CElemento s) // constructor { datos = d; siguiente = s; } } public CListaCircularSE() {} // constructor public int tamaño() { // Devuelve el número de elementos de la lista if (último == null) return 0; CElemento q = último.siguiente; // primer elemento int n = 1; // número de elementos while (q != último) { n++; q = q.siguiente; } return n; } public void añadirAlPrincipio(Object obj) { Curso: Estructuras de datos Docente : Ing. Hèctor Fiestas Bancayàn Universidad Los Ángeles de Chimbote Curso: Estructuras de datos // Añade un elemento al principio de la lista. // Crear el nuevo elemento. CElemento q = new CElemento(obj, null); if( último != null ) // existe una lista { q.siguiente = último.siguiente; último.siguiente = q; } else // inserción del primer elemento { último = q; último.siguiente = q; } } public void añadirAlFinal(Object obj) { // Añade un elemento al final de la lista. // Por lo tanto, último referenciará este nuevo elemento. // Crear el nuevo elemento. CElemento q = new CElemento(obj, null); if( último != null ) // existe una lista { q.siguiente = último.siguiente; último = último.siguiente = q; } else // inserción del primer elemento { último = q; último.siguiente = q; } } public Object borrar() { // Devuelve una referencia a los datos del primer elemento de // la lista y borra este elemento. if( último == null ) { System.err.println( "Lista vacía\n" ); return null; } CElemento q = último.siguiente; Object obj = q.datos; if( q == último ) último = null; else último.siguiente = q.siguiente; Curso: Estructuras de datos Docente : Ing. Hèctor Fiestas Bancayàn Universidad Los Ángeles de Chimbote Curso: Estructuras de datos return obj; // El elemento referenciado por q es enviado a la basura, al // quedar desreferenciado cuando finaliza este método por ser // q una variable local. } public Object obtener(int i) { // Obtener el elemento de la posición i int númeroDeElementos = tamaño(); if (i >= númeroDeElementos || i < 0) return null; CElemento q = último.siguiente; // primer elemento // Posicionarse en el elemento i for (int n = 0; n < i; n++) q = q.siguiente; // Retornar los datos return q.datos; } } ////////////////////////////////////////////////////////////////// Una vez que hemos escrito la clase CListaCircularSE, vamos a realizar una aplicación que utilizàndola cree una lista circular y ponga a prueba las distintas operaciones que sobre ella pueden realizarse. Los elementos de esta lista serán objetos de la clase CDatos utilizada en ejemplos anteriores. El código de esta aplicación puede ser el siguiente: ////////////////////////////////////////////////////////////////// // Crear una lista lineal circular simplemente enlazada // public class Test { public static void mostrarLista(CListaCircularSE lcse) { // Mostrar todos los elementos de la lista int i = 0, tam = lcse.tamaño(); CDatos obj; while (i < tam) { obj = (CDatos)lcse.obtener(i); System.out.println(i + ".- " + obj.obtenerNombre() + " " + obj.obtenerNota()); i++; } if (tam == 0) System.out.println("lista vacía"); Curso: Estructuras de datos Docente : Ing. Hèctor Fiestas Bancayàn Universidad Los Ángeles de Chimbote Curso: Estructuras de datos } public static void main(String[] args) { // Crear una lista circular vacía CListaCircularSE lcse = new CListaCircularSE(); // Leer datos y añadirlos a la lista String nombre; double nota; int i = 0; System.out.println("Introducir datos. Finalizar con Ctrl+Z."); System.out.print("nombre: "); while ((nombre = Leer.dato()) != null) { System.out.print("nota: "); nota = Leer.datoDouble(); lcse.añadirAlFinal(new CDatos(nombre, nota)); System.out.print("nombre: "); } // Añadir un objeto al principio lcse.añadirAlPrincipio(new CDatos("abcd", 10)); System.out.println("\n"); // Mostrar la lista System.out.println("Lista:"); mostrarLista(lcse); // Borrar el elemento primero CDatos obj = (CDatos)lcse.borrar(); // Mostrar la lista System.out.println("Lista:"); mostrarLista(lcse); } } **.** Curso: Estructuras de datos Docente : Ing. Hèctor Fiestas Bancayàn