Curso Interactivo de Estructuras de Datos
Carlos Eduardo G´ omez Montoya Profesor adscrito al Programa de Ingenier´ıa de Sistemas y Computaci´ on Facultad de Ingenier´ıa Universidad del Quind´ıo
ii
Curso Interactivo de Estructuras de Datos Este trabajo ha sido escrito con la intenci´ on de permitir su libre distribuci´on dentro de la comunidad acad´emica sin necesidad de solicitar autorizaci´on escrita por parte del autor. Derechos reservados c Noviembre de 2004 ° Este documento fue editado usando LATEX 2ε Armenia, Quind´ıo - Colombia
Presentaci´on El Curso Interactivo de Estructuras de Datos es un trabajo acad´emico presentado como requisito de ascenso en el escalaf´on docente de la Universidad del Quind´ıo, de la categor´ıa Profesor Asistente a la categor´ıa Profesor Asociado. Este trabajo se ha desarrollado durante los u ´ltimos tres a˜ nos con el fin de facilitar el trabajo de los estudiantes de Estructuras de Datos, una asignatura importante en el plan de estudios del programa Ingenier´ıa de Sistemas y Computaci´on de la Universidad del Quind´ıo en la ciudad de Armenia. El trabajo est´a conformado por varias partes: Una documentaci´on detallada donde se presentan los conceptos y las operaciones de las estructuras de datos m´as importantes como son la lista, la cola, la pila, el ´arbol y el grafo. Un conjunto de librer´ıas de clase que conforman unas APIs que facilite el desarrollo de aplicaciones con estructuras de datos, escrita en Java. Estas librer´ıas siguen muy cuidadosamente las indicaciones detalladas en la parte inicial, descrita en el ´ıtem anterior. Un conjunto de diez programas interactivos que permiten al estudiante crear y visualizar aplicaciones de las estructuras de datos b´asicas y adem´as ayudan a entrenarlo en el manejo de los m´etodos que ofrecen las APIs. Estos programas tienen la opci´on de guardar archivos con las construcciones del usuario y archivos de texto con el seguimiento de los comandos que el usuario ha utilizado. Estos archivos permiten realizar comparaci´on manual a un estudiante entre la secuencia de instrucciones que llevan a una estructura de datos a un estado particular y a la vez, son una importante herramienta de seguimiento para el docente.
´ PRESENTACION
iv
De manera adicional, se tienen ejemplos, ejercicios y programas de prueba que pueden ser utilizados en un curso de Estructuras de datos en cualquier universidad.
Una de las principales motivaciones por las cuales he querido desarrollar este trabajo es que a m´ı me parec´ıa que Estructuras de Datos era una materia muy compleja, dif´ıcil de estudiar y much´ısimo m´as dif´ıcil, tratar de ense˜ narla. Con el paso del tiempo he descubierto que la materia es agradable, formativa yu ´til, tanto para los estudiantes como para m´ı. Algunos aspectos para destacar en el trabajo:
M´as de 400 im´agenes cuidadosamente elaboradas que apoyan el contenido te´orico. M´as de 7.300 l´ıneas de c´odigo en las librer´ıas de clase. M´as de 7.200 l´ıneas de c´odigo en los programas de prueba. M´as de 20.000 l´ıneas de c´odigo en los programas interactivos. M´as de 80 ejercicios.
Sobre las referencias bibliogr´ aficas Este trabajo es una visi´on personal de las principales estructuras de datos que se trabajan en las ciencias de la computaci´on. Por lo tanto, los libros consultados se utilizaron para estudiar las estructuras de datos y precisar algunos conceptos, especialmente en la introducci´on a cada cap´ıtulo. Por esta raz´on no se utilizaron citas textuales de ning´ un libro, aunque deseo destacar tres libros que consult´e con mayor frecuencia: Estructuras de datos en C++, de C´esar Becerra; Estructuras de datos en Java, de Mark Allen Weiss y Estructura de datos: Libro de problemas de Luis Joyanes y otros.
v
Acerca del autor Carlos Eduardo G´ omez Montoya. Licenciado en Matem´aticas y Computaci´on de la Universidad del Quind´ıo y Especialista en Redes de Comunicaci´on de la Universidad del Valle. Aceptado en la Universidad de los Andes de Bogot´a - Colombia para iniciar pr´oximamente estudios de Maestr´ıa en Ingenier´ıa de Sistemas y Computaci´on. Profesor de tiempo completo de la Universidad del Quind´ıo adscrito al programa Ingenier´ıa de Sistemas y Computaci´on. Autor de diferentes obras en el ´area de la Ingenier´ıa de Sistemas e inform´atica. carloseg@uniquindio.edu.co
vi
´ PRESENTACION
Agradecimientos Llevar a feliz t´ermino este trabajo ha sido una labor de casi tres a˜ nos de duraci´on. No puedo finalizar sin mencionar algunas personas que contribuyeron para que saliera adelante. Quiero expresar mis agradecimientos: A Juli´an Esteban Guti´errez Posada, compa˜ nero y amigo, por su constante asesor´ıa y acompa˜ namiento. A los compa˜ neros de trabajo quienes me apoyaron durante este largo proceso, por sus aportes, ideas y revisiones: Robinson Pulgar´ın Giraldo, Leonardo Hern´andez Rodr´ıguez, Sergio Augusto Cardona Torres, Diego Fernando Mar´ın Sanabria y Jorge Iv´an Quintero Salazar. A la profesora del curso Matem´aticas discretas en el programa Ingenier´ıa de Sistemas y Computaci´on de la Universidad del Quind´ıo, Ang´elica Mar´ıa Ram´ırez, y su auxiliar docente, el estudiante Duberney Ram´ırez Mesa por su amable colaboraci´on en la parte final de este trabajo. A todos los estudiantes a quienes he tenido la oportunidad de orientar en el curso Estructuras de Datos en la Universidad del Quind´ıo, principales colaboradores y a quienes les he preparado todo este material. Finalmente a mi Familia, Olga Luc´ıa, Pablo y Mart´ın, las personas m´as sacrificadas por la cantidad de tiempo en el que no los he acompa˜ nado por estar dedicado a este trabajo.
viii
AGRADECIMIENTOS
´Indice general
Presentaci´ on
III
Agradecimientos
VII
1. Preliminares
I
1
1.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2. Justificaci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.3. Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
1.3.1. Objetivo general . . . . . . . . . . . . . . . . . . . . .
3
1.3.2. Objetivos espec´ıficos . . . . . . . . . . . . . . . . . . .
3
1.4. Tem´atica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
Documentaci´ on r´ apida
7
2. Resumen general de operaciones
9
2.1. Introducci´on . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2. Generalidades . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.3. Nodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.3.1. Componentes de un nodo
. . . . . . . . . . . . . . . . 12
2.3.2. Operaciones de un nodo . . . . . . . . . . . . . . . . . 13 2.4. Enlaces
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.4.1. Componentes de un enlace . . . . . . . . . . . . . . . . 14 ix
´INDICE GENERAL
x
2.4.2. Operaciones de un enlace . . . . . . . . . . . . . . . . . 15 2.5. Lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.5.1. Componentes de una lista . . . . . . . . . . . . . . . . 17 2.5.2. Operaciones de una lista . . . . . . . . . . . . . . . . . 18 2.6. Cola . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.6.1. Componentes de una cola . . . . . . . . . . . . . . . . 20 2.6.2. Operaciones de una cola . . . . . . . . . . . . . . . . . 20 2.7. Pila
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.7.1. Componentes de una pila . . . . . . . . . . . . . . . . . 22 2.7.2. Operaciones de una pila . . . . . . . . . . . . . . . . . 22 ´ 2.8. Arbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 2.8.1. Componentes de un ´arbol . . . . . . . . . . . . . . . . 25 2.8.2. Operaciones de una ´arbol . . . . . . . . . . . . . . . . 25 2.9. Grafo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.9.1. Componentes de un grafo . . . . . . . . . . . . . . . . 28 2.9.2. Operaciones de un grafo . . . . . . . . . . . . . . . . . 28
II
Software Interactivo
33
3. Software Interactivo
35
III
57
Documentaci´ on detallada
4. Nodos y enlaces
59
4.1. Componentes de un Nodo . . . . . . . . . . . . . . . . . . . . 59 4.2. Operaciones de un nodo . . . . . . . . . . . . . . . . . . . . . 61 4.3. Detalles de las operaciones . . . . . . . . . . . . . . . . . . . . 63 4.3.1. Construcci´on . . . . . . . . . . . . . . . . . . . . . . . 63 4.3.2. Modificaci´on . . . . . . . . . . . . . . . . . . . . . . . . 65 4.3.3. An´alisis . . . . . . . . . . . . . . . . . . . . . . . . . . 74
´INDICE GENERAL
xi
5. Lista
83
5.1. Lista doblemente enlazada: Conceptos
. . . . . . . . . . . . . 85
5.2. Operaciones de una lista . . . . . . . . . . . . . . . . . . . . . 88 5.2.1. Construcci´on . . . . . . . . . . . . . . . . . . . . . . . 90 5.2.2. Modificaci´on . . . . . . . . . . . . . . . . . . . . . . . . 90 5.2.3. An´alisis . . . . . . . . . . . . . . . . . . . . . . . . . . 121 5.2.4. Localizaci´on . . . . . . . . . . . . . . . . . . . . . . . . 125 5.2.5. Persistencia . . . . . . . . . . . . . . . . . . . . . . . . 129 6. Cola
131
6.1. Cola: Conceptos . . . . . . . . . . . . . . . . . . . . . . . . . . 132 6.2. Operaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 6.2.1. Construcci´on . . . . . . . . . . . . . . . . . . . . . . . 133 6.2.2. Modificaci´on . . . . . . . . . . . . . . . . . . . . . . . . 133 6.2.3. An´alisis . . . . . . . . . . . . . . . . . . . . . . . . . . 135 6.2.4. Persistencia . . . . . . . . . . . . . . . . . . . . . . . . 138 7. Pila
139
7.1. Pila: Conceptos . . . . . . . . . . . . . . . . . . . . . . . . . . 140 7.2. Operaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 7.2.1. Construcci´on . . . . . . . . . . . . . . . . . . . . . . . 141 7.2.2. Modificaci´on . . . . . . . . . . . . . . . . . . . . . . . . 141 7.2.3. An´alisis . . . . . . . . . . . . . . . . . . . . . . . . . . 143 7.2.4. Persistencia . . . . . . . . . . . . . . . . . . . . . . . . 146
´INDICE GENERAL
xii ´ 8. Arbol
147
8.1. Clases de ´arboles . . . . . . . . . . . . . . . . . . . . . . . . . 147 8.2. Aplicaciones de los ´arboles . . . . . . . . . . . . . . . . . . . . 148 8.3. Conceptos generales . . . . . . . . . . . . . . . . . . . . . . . . 149 8.4. Formas de recorrer un ´arbol . . . . . . . . . . . . . . . . . . . 150 8.5. Componentes de un ´arbol . . . . . . . . . . . . . . . . . . . . 150 8.6. Operaciones sobre un ´arbol n-ario . . . . . . . . . . . . . . . . 154 8.7. Detalles de las operaciones . . . . . . . . . . . . . . . . . . . . 157 8.7.1. Construcci´on . . . . . . . . . . . . . . . . . . . . . . . 157 8.7.2. Modificaci´on . . . . . . . . . . . . . . . . . . . . . . . . 158 8.7.3. An´alisis . . . . . . . . . . . . . . . . . . . . . . . . . . 187 8.7.4. Localizaci´on . . . . . . . . . . . . . . . . . . . . . . . . 201 8.7.5. Persistencia . . . . . . . . . . . . . . . . . . . . . . . . 204 9. Otras clases de ´ arboles
207
9.1. Arbol binario de b´ usqueda . . . . . . . . . . . . . . . . . . . . 207 9.1.1. Operaciones del ´arbol binario de b´ usqueda . . . . . . . 209 9.1.2. C´odigo fuente . . . . . . . . . . . . . . . . . . . . . . . 215 ´ 9.2. Arbol AVL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 9.2.1. Operaciones en un ´arbol AVL . . . . . . . . . . . . . . 219 9.2.2. C´odigo fuente . . . . . . . . . . . . . . . . . . . . . . . 224 9.3. Arboles B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 9.3.1. Operaciones . . . . . . . . . . . . . . . . . . . . . . . . 229 ´ 9.4. Arboles B+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 9.4.1. Operaciones en un ´arbol B+ . . . . . . . . . . . . . . . 234
´INDICE GENERAL
xiii
10.Grafo
237
10.1. Aplicaciones de un grafo . . . . . . . . . . . . . . . . . . . . . 238 10.2. Conceptos generales . . . . . . . . . . . . . . . . . . . . . . . . 238 10.2.1. Conceptos sobre nodos . . . . . . . . . . . . . . . . . . 238 10.2.2. Conceptos sobre enlaces . . . . . . . . . . . . . . . . . 239 10.2.3. Conceptos sobre grafos . . . . . . . . . . . . . . . . . . 240 10.3. Formas de recorrer un grafo . . . . . . . . . . . . . . . . . . . 243 10.4. Componentes de un grafo
. . . . . . . . . . . . . . . . . . . . 244
10.5. Operaciones de un grafo . . . . . . . . . . . . . . . . . . . . . 244 10.6. Detalles de las operaciones . . . . . . . . . . . . . . . . . . . . 248 10.6.1. Construcci´on . . . . . . . . . . . . . . . . . . . . . . . 248 10.6.2. Modificaci´on . . . . . . . . . . . . . . . . . . . . . . . . 248 10.6.3. An´alisis . . . . . . . . . . . . . . . . . . . . . . . . . . 262 10.6.4. Recorridos . . . . . . . . . . . . . . . . . . . . . . . . . 272 10.6.5. Persistencia . . . . . . . . . . . . . . . . . . . . . . . . 274
IV
C´ odigo Fuente
275
11.Instalaci´ on del paquete
277
12.Ejemplos
281
13.C´ odigo Fuente
285
13.1. Modelos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 13.2. Compilar las librer´ıas . . . . . . . . . . . . . . . . . . . . . . . 307 13.3. Documentaci´on . . . . . . . . . . . . . . . . . . . . . . . . . . 309 14.Pruebas
311
14.1. Compilar un archivo de prueba . . . . . . . . . . . . . . . . . 320 14.2. Ejecutar un archivo de prueba . . . . . . . . . . . . . . . . . . 322 14.3. Pruebas de compatibilidad . . . . . . . . . . . . . . . . . . . . 322
´INDICE GENERAL
xiv
V
Ejercicios
325
15.Nodos
327
16.Lista
339
17.Cola
349
18.Pila
351
´ 19. Arbol
357
20.Grafo
361
Conclusiones
365
Bibliograf´ıa
367
1
Preliminares 1.1.
Introducci´ on
Estructuras de Datos es una asignatura fundamental en cualquier programa de pregrado en Ingenier´ıa de Sistemas, en Colombia y en programas similares en otros lugares del mundo. Las aplicaciones de las estructuras de datos en las ciencias de la computaci´on son innumerables. Entre ellas se podr´ıan mencionar los aut´omatas, compiladores, redes de computadores, sistemas operativos, bases de datos, modelamiento de software, al igual que muchas aplicaciones en inteligencia artificial. La ense˜ nanza de este tema no ha sido f´acil debido a la diversidad de temas y a la cantidad de conceptos que el estudiante debe conocer y administrar, limitando un poco su aplicaci´on por parte de ellos. Por otra parte, es una necesidad de todos los programas acad´emicos, avanzar en la modernizaci´on de los contenidos de las diferentes asignaturas y Estructuras de Datos no puede ser la excepci´on. El prop´osito fundamental del trabajo es producir un material de apoyo a esta asignatura, tanto documental como interactivo, el cual incluya im´agenes y ejemplos ilustrativos.
CAP´ITULO 1. PRELIMINARES
2
Este desarrollo utilizar´a la programaci´on orientada a objetos y el lenguaje de programaci´on Java. Con ellos se podr´an construir librer´ıas gen´ericas de clase, parametrizadas. Con estas librer´ıas los estudiantes podr´an comprender los conceptos fundamentales de las estructuras de datos y estar´an en condiciones de crear sus propias aplicaciones y nuevas librer´ıas, ajustadas a sus necesidades. Cabe anotar que lo que se pretende realizar es un material did´actico que les ayude a los estudiantes a apropiarse de los conceptos de la asignatura, no un conjunto de librer´ıas para que ellos simplemente las utilicen.
1.2.
Justificaci´ on
En la actualidad, el programa de Ingenier´ıa de Sistemas y Computaci´on de la Universidad del Quind´ıo no dispone de un material did´actico que facilite el aprendizaje de la asignatura Estructuras de Datos, una materia fundamental en el nuevo curr´ıculo del programa. Si bien es cierto que existen numerosos libros de texto que pueden apoyar esta labor, al profesor le corresponde una dispendiosa tarea de adaptar los ejemplos de diferentes autores para una adecuada utilizaci´on en la asignatura. Adem´as, algunos de estos libros incluyen traducciones que no son de la mejor calidad, ejemplos en cuyo desarrollo han sido utilizadas t´ecnicas anticuadas de programaci´on, o ejemplos que son muy dif´ıciles de seguir y entender. Estos factores afectan el aprendizaje de los estudiantes. Este material puede contribuir notablemente en el desarrollo y proyecci´on de esta asignatura, la cual es de vital importancia, tanto en el plan de estudios actual como en el nuevo. Por otra parte, no se puede olvidar que en la acreditaci´on de los programas es fundamental la producci´on intelectual de los docentes, los cuales deben desarrollar sus propios materiales de enseanza y no limitarse a trabajar con los textos gu´ıa producidos por terceros.
1.3. OBJETIVOS
1.3.
Objetivos
1.3.1.
Objetivo general
3
Analizar, dise˜ nar e implementar un material did´actico, documental e interactivo que ayude a la ensenanza de la asignatura Estructuras de Datos en el programa Ingenier´ıa de Sistemas y Computaci´on de la Universidad del Quind´ıo.
1.3.2.
Objetivos espec´ıficos
Recopilar la informaci´on te´orica necesaria sobre las estructuras de datos m´as utilizadas y sus aplicaciones en las ciencias de la computaci´on. Utilizar el an´alisis y dise˜ no orientado a objetos para guiar el desarrollo de aplicaciones con estructuras de datos. Construir un software que le permita al estudiante implementar estructuras de datos e interactuar con ellas. Construir un sitio Web para agrupar el contenido te´orico, los ejemplos y ejercicios, adem´as de los enlaces que permitan descargar el c´odigo fuente utilizado. Apoyar el proceso de ense˜ nanza aprendizaje de la asignatura Estructuras de Datos.
1.4.
Tem´ atica
Los temas a tratar en este trabajo son: Nodos y enlaces Lista • Lista sencillamente enlazada • Lista circular sencillamente enlazada • Lista doblemente enlazada • Lista circular doblemente enlazada
CAP´ITULO 1. PRELIMINARES
4 Cola Pila ´ Arbol ´ • Arbol n-ario ´ • Arbol binario • Otros tipo de ´arboles ◦ ◦ ◦ ◦
´ Arbol ´ Arbol ´ Arbol ´ Arbol
de b´ usqueda AVL B B+
Grafo • Grafo dirigido • Grafo no dirigido De cada uno de los temas antes mencionados, se va a construy´o una clase que sirve como interfaz de programaci´on de aplicaciones (API) para que los estudiantes la puedan utilizar como herramienta de desarrollo. Estas APIs menciondas son parametrizables lo que les da un amplio potencial de aplicaci´on, no solo mientras el estudiante cursa la asignatura, sino para su uso en asignaturas posteriores y al terminar su carrera. Naturalmente, se escribi´o la documentaci´on que le permita al estudiante entender cada uno de los conceptos involucrados en los m´etodos que se ofrecen, apoyado en un buen n´ umero de im´agenes que faciliten la interpretaci´on de los diferentes contenidos. Por otra parte, se desarroll´o un software interactivo que le va a permitir al estudiante construir sus propias estructuras de datos, de las cuales puede ver paso a paso el proceso de creaci´on y edici´on, con la opci´on de guardarlas en archivos. Tambi´en es posible hacer seguimiento a la secuencia de instrucciones utilizadas por el estudiante para la creaci´on de sus estructuras, gracias a la
´ 1.4. TEMATICA
5
generaci´on de archivos de historial. Estos archivos de historial le van a facilitar el estudio y comprensi´on de los conceptos asociados a cada una de las APIs anteriormente mencionadas. Sobre el tema Otros tipos de ´arboles se har´a una introducci´on a los conceptos te´oricos fundamentales, sin llegar a una implementaci´on. Todo esto ser´a reunido en un sitio Web para facilitar la difusi´on de este material acad´emico, para que su aprovechamiento no sea u ´nicamente dentro de la Universidad del Quind´ıo, sino con el fin de difundirlo en la comunidad acad´emica.
6
CAP´ITULO 1. PRELIMINARES
Parte I Documentaci´ on r´ apida
7
2
Resumen general de operaciones
Este cap´ıtulo resume los cap´ıtulos que hacen parte de este trabajo, en donde se especifica con detalle la implementaci´on orientada a objetos de las principales estructuras de datos utilizadas en las Ciencias de la Computaci´on, como son: lista, cola, pila, ´arbol y grafo. El an´alisis de las propiedades de cada una de las diferentes estructuras de datos se ha realizado utilizando la orientaci´on a objetos y se han aplicado algunas de las principales carater´ısticas de los objetos como son la encapsulaci´on, la herencia y el polimorfismo. Se escribieron las APIs correspondientes en lenguaje Java versi´on 1.4 y con el fin de facilitar su comprensi´on se han creado im´agenes para explicar detalladamente los diferentes pasos que componen cada operaci´on.
2.1.
Introducci´ on
El presente trabajo es una producci´on acad´emica realizada con el fin de facilitar el desarrollo de un curso b´asico de Estructuras de Datos en un programa de pregrado en Ingenier´ıa de Sistemas, el cual puede ser aplicado en cualquier universidad. El Curso Interactivo de Estructuras de Datos se compone de:
10
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES Un conjunto de APIs o librer´ıas de clase para diez (10) estructuras de datos diferentes, las cuales se pueden construir a partir de la clase Node.java como elemento fundamental. Estas clases est´an agrupadas en el paquete EstrDatos. Las clases que conforman el paquete son: 1. Node.java 2. Link.java 3. List.java 4. SingleList.java 5. CircularSingleList.java 6. DoubleList.java 7. CircularDoubleList.java 8. Queue.java 9. Stack.java 10. Tree.java 11. BinaryTree.java 12. Graph.java 13. DirectedGraph.java 14. UnDirectedGraph.java 15. EstrDatosException.java Cada una de las principales estructuras de datos, en sus respectivos cap´ıtulos: 1. Resumen general de operaciones 2. Nodos y enlaces 3. Lista 4. Cola 5. Pila 6. Arbol 7. Grafo
2.2. GENERALIDADES
11
Un conjunto de diez (10) programas interactivos, cada uno agrupado en un paquete diferente. Los programas interactivos son: 1. LSEInteractivo.jar 2. LCSEInteractivo.jar 3. LDEInteractivo.jar 4. LCDEInteractivo.jar 5. ColaInteractivo.jar 6. PilaInteractivo.jar 7. ANInteractivo.jar 8. ANInteractivo.jar 9. GDInteractivo.jar 10. GNDInteractivo.jar
2.2.
Generalidades
Una estructura de datos es una colecci´on de datos, no siempre del mismo tipo, los cuales se relacionan entre s´ı y pueden funcionar como una sola unidad. Las estructuras de datos se dividen en est´aticas o de tama˜ no fijo y din´amicas o de tama˜ no variable. Las est´aticas, generalmente desperdician parte de la memoria asignada a ellas. Por el contrario, las estructuras de datos din´amicas definen su tama˜ no en tiempo de ejecuci´on. Entre las estructuras de datos m´as importantes se tienen las listas enlazadas, las colas, las pilas, los ´arboles y los grafos. Cada una de ellas puede ser construida de manera independiente o como la combinaci´on de nodos y enlaces. Se ha pensado en el enfoque orientado a objetos sobre Java por ser una forma moderna de hacer desarrollo de software, adem´as de la versatilidad y funcionalidad que ofrece Java, no solo por ser de uso libre, sino tambi´en por su portabilidad, lo que permite independencia del hardware y el sistema operativo en el cual pueda ser utilizado. A continuaci´on se puede apreciar un resumen de los atributos y m´etodos que conforman cada una de las clases que hacen parte del paquete EstrDatos.
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
12
2.3.
Nodos
Las estructuras de datos se pueden dise˜ nar a partir de la combinaci´on adecuada de nodos y enlaces. Un nodo, en este trabajo, es un elemento que puede almacenar una referencia a un objeto de cualquier tipo, permitiendo incluso que diferentes nodos de una estructura de datos tengan almacenadas referencias de tipos de datos diferentes. Ver figura 2.3. La clase Node.java est´a conformada por los atributos y m´etodos que se describen a continuaci´on.
2.3.1.
Componentes de un nodo
En un nodo se pueden destacar los siguientes atributos privados: Object
data
String
name
int
numberInputLinks
int
maxPort
Vector
port
boolean flag Ver figura 2.1.
Figura 2.1: Nodo
2.3. NODOS
2.3.2.
13
Operaciones de un nodo
Las operaciones p´ ublicas a realizar sobre un nodo se pueden clasificar de la siguiente manera: Construcci´ on: 1. Node ( ) 2. Node ( String newName ) 3. Node ( int max ) 4. Node ( int max, String newName ) Modificaci´ on: 1. void set
( Object newData )
2. void setName
( String newName )
3. void setMaxPort ( int max ) 4. void setWeight
( int numberPort, double weight )
5. void link
( Node nodeLink, int numberPort, double newWeight )
6. void link
( Node nodeLink, int numberPort )
7. void unLink
( int numberPort )
8. void setFlag
( boolean valor )
9. void less
( ) (Es una operaci´on protegida)
10. void plus
( ) (Es una operaci´on protegida)
An´ alisis: 1. Object
get
( )
2. String
getName
( )
3. int
getNumberInputLinks ( )
4. int
getMaxPort
( )
5. int
getSize
( )
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
14
6. Link
getLink
( int numberPort )
7. double
getWeight
( int numberPort )
8. int
getLeastNumberPort
( )
9. String
getOutputLinks
( )
10. boolean getFlag
( )
11. boolean isData
( )
12. boolean isLink
( int numberPort )
13. int
search
( Object element )
14. Node
whoLink
( int numberPort )
15. String
toString
( )
Para m´as detalle, ver el cap´ıtulo Nodos y Enlaces en la p´agina 59.
2.4.
Enlaces
Un enlace es un objeto que le permite a un nodo, conectarse con otro. La clase Link est´a conformada por los atributos y m´etodos que se describen a continuci´on.
2.4.1.
Componentes de un enlace
Un enlace, en este trabajo, est´a compuesto por tres campos privados: Node
target
double weight int
backPort
Ver figura 2.2.
2.5. LISTA
15
Figura 2.2: Enlace
2.4.2.
Operaciones de un enlace
Las operaciones p´ ublicas a realizar sobre un enlace se pueden clasificar de la siguiente manera: Construcci´ on: 1. Link ( Node newTarget, double newWeight ) Modificaci´ on: 1. void setTarget
( Node newTarget
2. void setWeight
( double newWeight )
3. void setBackPort ( int newBackPort
) )
An´ alisis: 1. Node
getTarget
( )
2. double getWeight
( )
3. int
2.5.
getBackPort ( )
Lista
La lista es una estructura de datos lineal. En una lista, usualmente los datos est´an organizados en la memoria en posiciones no adyacentes, pero los datos se mantienen unidos a trav´es de enlaces. Por esta raz´on, reciben el nombre de listas enlazadas. En este trabajo, cada elemento de la lista es un nodo. En cada nodo se almacena una referencia a un objeto el cual puede ser de cualquier tipo de datos.
16
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
Entre las clases de listas enlazadas m´as frecuentemente utilizadas se encuentran: Lista sencillamente enlazada: Es una lista en la cual cada nodo tiene una conexi´on con un nodo hacia adelante. Ver figura 2.3.
Figura 2.3: Lista sencillamente enlazada
Lista circular sencillamente enlazada: Es una lista sencillamente enlazada en la cual el siguiente nodo del u ´ltimo nodo de la lista es el primer nodo. Ver figura 2.4.
Figura 2.4: Lista circular sencillmente enlazada
Lista doblemente enlazada: Es una lista en la cual cada nodo tiene una conexi´on con un nodo hacia adelante y otra conexi´on con un nodo hacia atr´as. Ver figura 2.5.
Figura 2.5: Lista doblemente enlazada
Lista circular doblemente enlazada: Es una lista doblemente enlazada en la cual se tienen conectados los nodos inicial y final, de manera que el siguiente del u ´ltimo nodo de la lista es el primer nodo y el anterior al primer nodo de la lista es el u ´ltimo. Ver figura 2.6.
2.5. LISTA
17
Figura 2.6: Lista circular doblemente enlazada
Las clases: SingleList.java (lista sencillamente enlazada) CircularSingleList.java (lista circular sencillamente enlazada) DoubleList.java (lista doblemente enlazada) CircularDoubleList.java (lista circular doblemente enlazada) est´an conformadas por los atributos y m´etodos que se describen a continuaci´on.
2.5.1.
Componentes de una lista
En una lista, en este trabajo, tiene los siguientes atributos protegidos1 : Node
first
Node
current
Node
last
int
length
boolean changed 1
Por decisi´on arbitraria del autor, se han dejado los atributos como protegidos por si se hace necesario especializar la clase utilizando herencia.
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
18
2.5.2.
Operaciones de una lista
Las operaciones p´ ublicas a realizar sobre una lista se pueden clasificar de la siguiente manera: Construcci´ on: 1. SingleList ( ) 2. DoubleList ( ) 3. CircularSingleList ( ) 4. CircularDoubleList ( ) Modificaci´ on: 1. void newList
( )
2. void add
( Object element )
3. void insertLeft
( Object element )
4. void insertRight ( Object element ) 5. void update
( Object element )
6. void remove
( )
An´ alisis: 1. Object
get
( )
2. int
getSize
( )
3. int
getIndex
( )
4. boolean getChanged
( )
5. boolean isValidCurrent ( ) 6. String
toString
Localizaci´ on: 1. void goFirst ( ) 2. void goLast
( )
( )
2.6. COLA
19
3. void goNext
( )
4. void goBack
( )
5. void goTo
( int position )
Persistencia: 1. void
save ( String nameFile )
2. SingleList
load ( String nameFile )
3. DoubleList
load ( String nameFile )
4. CircularSingleList load ( String nameFile ) 5. CircularDoubleList load ( String nameFile ) Para m´as detalle, ver el cap´ıtulo Lista en la p´agina 83.
2.6.
Cola
Una cola es una estructura de datos similar a una lista sencillamente enlazada, pero con algunas restricciones. En una cola, los datos salen en el mismo orden en que han ingresado, es decir, el primero en entrar es el primero en ser atendido. Por otra parte, una cola no se puede recorrer, porque solo hay acceso a un elemento de la cola, el que se encuentre en la primera posici´on. Para que sea posible atender otro elemento, es necesario que el primer elemento de la cola sea eliminado de ella. Una cola se compone de nodos en los cuales se pueden almacenar referencias a objetos. Los nodos est´an enlazados, sin embargo, el manejo que se le da a los enlaces es interno y el usuario no tiene acceso a ellos. Ver figura 2.7. La clase Queue.java est´a conformada por los atributos y m´etodos que se describen a continuaci´on.
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
20
Figura 2.7: Cola
2.6.1.
Componentes de una cola
En una cola, en este trabajo, tiene los siguientes atributos protegidos: SingleList queue boolean
2.6.2.
changed
Operaciones de una cola
Las operaciones p´ ublicas a realizar sobre una cola se pueden clasificar de la siguiente manera: Construcci´ on: 1. Queue ( ) Modificaci´ on: 1. void
newQueue
( )
2. void
insert
( Object element )
3. Object getAndRemove ( ) An´ alisis: 1. Object
get
( )
2. int
search
( Object element )
3. boolean isEmpty
( )
2.7. PILA 4. String
21 toString ( )
Persistencia: 1. void save
( String nameFile )
2. Queue load ( String nameFile ) Para m´as detalle, ver el cap´ıtulo Cola en la p´agina 131.
2.7.
Pila
Una pila es una estructura de datos similar a una lista sencillamente enlazada, pero con algunas restricciones. En una pila, los datos salen en el orden contrario al orden en que han ingresado, es decir, el primero en entrar es el u ´ltimo en ser atendido. Por otra parte, una pila no se puede recorrer, porque solo hay acceso a un elemento de la pila, el que se encuentre en la primera posici´on. Para que sea posible atender otro elemento, es necesario que el primer elemento de la pila sea eliminado de ella. Una pila se compone de nodos en los cuales se pueden almacenar referencias a objetos. Los nodos est´an enlazados, sin embargo, el manejo que se le da a los enlaces es interno y el usuario no tiene acceso a ellos. Ver figura 2.8. La clase Stack.java est´a conformada por los atributos y m´etodos que se describen a continuaci´on.
Figura 2.8: Pila
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
22
2.7.1.
Componentes de una pila
En una pila, en este trabajo, tiene los siguientes atributos protegidos: SingleList stack boolean
2.7.2.
changed
Operaciones de una pila
Las operaciones p´ ublicas a realizar sobre una pila se pueden clasificar de la siguiente manera: Construcci´ on: 1. Stack ( ) Modificaci´ on: 1. void
newStack ( )
2. void
push
3. Object pop
( Object element ) ( )
An´ alisis: 1. Object
peek
( )
2. int
search
( Object element )
3. boolean isEmpty 4. String
( )
toString ( )
´ 2.8. ARBOL
23
Persistencia: 1. void save
( String nameFile )
2. Queue load ( String nameFile ) Para m´as detalle, ver el cap´ıtulo Pila en la p´agina 139.
2.8.
´ Arbol
Un ´arbol es una de las estructuras de datos m´as utilizadas en las ciencias de la computaci´on. Est´a formado por nodos y enlaces de una manera jer´arquica, donde se depende de un nodo principal llamado nodo ra´ız, del cual se desprenden otros nodos llamados hijos del nodo ra´ız. A su vez, de cada uno de los hijos del nodo ra´ız se pueden derivar hijos e hijos de los hijos, y as´ı sucesivamente. Existen ´arboles con enlaces descendentes u ´nicamente y ´arboles con enlace al padre que pueden ser visitados de arriba hacia abajo y viceversa. La implementaci´on propuesta en este trabajo permite crear ´arboles con enlace al padre. Es importante anotar que cada nodo del ´arbol puede ser el nodo ra´ız de un sub´arbol que hace parte del ´arbol. Ver figura 2.9.
24
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
´ Figura 2.9: Arbol
Existe una clase de ´arbol, restringido a m´aximo dos hijos, la cual se conoce con el nombre de ´arbol binario y tiene muchas aplicaciones en las ciencias de la computaci´on. Ver figura 2.10.
´ Figura 2.10: Arbol binario Las clases Tree.java y BinaryTree.java est´an conformadas por los atributos y m´etodos que se describen a continuaci´on.
´ 2.8. ARBOL
2.8.1.
25
Componentes de un ´ arbol
Un ´arbol, en este trabajo, tiene los siguientes atributos protegidos: Node
root
Node
current
int
size
int
maxPort
int
height
boolean changed int
2.8.2.
auxiliar
Operaciones de una ´ arbol
Las operaciones p´ ublicas a realizar sobre un ´arbol se pueden clasificar de la siguiente manera: Construcci´ on: 1. Tree
( )
2. Tree
( int max )
3. BinaryTree ( ) Modificaci´ on: 1. void newTree
( )
2. void addRoot
( Object element )
3. void addSon
( Object element, int index )
4. void update
( Object element )
5. void removeSubTree ( ) 6. void removeLeaf
( )
26
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES An´ alisis: 1. boolean currentHasSon
( int index )
2. Object
( )
get
3. boolean getChanged
( )
4. int
getSize
( )
5. int
getIndex
( )
6. int
getHeight
( )
7. void
getHeight
( Node nodo )
8. int
getWeight
( )
9. int
getLeastNumberPort ( )
10. boolean isValidCurrent
( )
11. boolean isEmpty
( )
12. boolean currentIsLeaf
( )
13. boolean currentIsRoot
( )
14. String
( )
toString
Recorridos: 1. void preOrder
( SingleList lista )
2. void postOrder ( SingleList lista ) 3. void levels
( SingleList lista )
4. void inOrder
( SingleList lista )
Nota: El recorrido inOrder aplica solo para ´arboles binarios. Localizaci´ on: 1. void goRoot
( )
2. void goParent ( ) 3. void goSon
( int index )
2.9. GRAFO
27
Persistencia: 1. void save
( String nameFile )
2. Tree load
( String nameFile )
3. BinaryTree load ( String nameFile ) Para m´as detalle, ver el cap´ıtulo Arbol en la p´agina 147.
2.9.
Grafo
Un grafo es una estructura de datos formada por un conjunto de nodos o v´ertices y un conjunto de enlaces o aristas que conecta a los nodos. Si los enlaces tienen direcci´on o sentido, se dice que el grafo es dirigido, tambi´en llamado d´ıgrafo. Ver figura 2.11.
Figura 2.11: Grafo dirigido
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
28
Si los enlaces no tienen direcci´on, se asume que son bidireccionales. En este caso, se denomina grafo no dirigido. Ver figura 2.12.
Figura 2.12: Grafo no dirigido
2.9.1.
Componentes de un grafo
Un grafo, en este trabajo, tiene los siguientes atributos protegidos: Hashtable graph int
size
boolean
changed
Node
initial
2.9.2.
Operaciones de un grafo
Las operaciones p´ ublicas a realizar sobre un grafo se pueden clasificar de la siguiente manera:
2.9. GRAFO
29
Construcci´ on: 1. DirectedGraph
( )
2. UnDirectedGraph ( ) Modificaci´ on: 1. void add
( String newName, Object element
2. void add
( String newName, Object element, int newMaxPort )
3. void remove
( String name )
4. void setInitial ( String name ) 5. void setWeight
( String name, int numberPort, double newWeight )
6. void set
( String name, Object data )
7. void setMaxPort ( String name, int newMaxPort ) 8. void newGraph
( )
9. void setChanged ( boolean valor ) Modificaci´ on (Aplican solo para grafos dirigidos): 1. void link
( String source, String target, int outPort, double weight )
2. void link
( String source,
3. void link
( String source, String target, int numberPort )
4. void unLink ( String name,
String target )
int positionPort )
Modificaci´ on (Aplican solo para grafos no dirigidos): 1. void link
( String source, String target, int outPort, double weight )
2. void link
( String source,
3. void link
( String source, String target, int outPort )
String target )
30
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES 4. void link
( String source, String target, int outPort, int inPort, double weight )
5. void unLink
( String name, int numberPort )
6. void setWeight ( String name, int numberPort, double newWeight ) An´ alisis: 1. Object
get
( String name )
2. boolean
getChanged
( )
3. String
getOutputLinks
( String name )
4. Hashtable getHashtable
( )
5. int
getLeastNumberPort
( String name )
6. int
getNumberInputLinks ( String name )
7. int
getMaxPort
( String name )
8. Node
getNode
( String name )
9. int
getSize
( )
10. int
getSizeNode
( String name )
11. double
getWeight
( String name, int numberPort )
12. Node
getInitial
( )
13. boolean
isInGraph
( String name )
14. boolean
isLink
( String name, int numberPort )
15. int
search
( String name, Object element )
16. Node
whoLink
( String name, int positionPort )
17. String
toString
( )
2.9. GRAFO
31
Recorridos: 1. void depth ( SingleList lista ) 2. void width ( SingleList lista ) Persistencia: 1. void
save ( String nameFile )
2. DirectedGraph
load ( String nameFile )
3. UnDirectedGraph load ( String nameFile ) Para m´as detalle, ver el cap´ıtulo Grafo en la p´agina 237.
32
CAP´ITULO 2. RESUMEN GENERAL DE OPERACIONES
Parte II Software Interactivo
33
3
Software Interactivo Con el fin de facilitar el aprendizaje de los estudiantes de un curso de Estructuras de datos, se construy´o el software interactivo. El software interactivo es un conjunto de diez programas que le permiten al estudiante crear, editar, visualizar y guardar sus propias construcciones con estructuras de datos utilizando los diferentes m´etodos que ofrece cada una de las librer´ıas de clase que conforman el paquete EstrDatos. A trav´es de los programas interactivos el estudiante construye paso a paso un caso particular de una lista, una cola, una pila, un ´arbol o un grafo y puede ver como va cambiando su estructura de datos a medida que utiliza los comandos que ofrece cada programa. Estas aplicaciones facilitan el aprendizaje del estudiante porque puede practicar el uso de los m´etodos que encuentra en las librer´ıas. La u ´nica restricci´on que se tiene al utilizar los programas interactivos es que las estructuras de datos tienen como campo de datos, valores de tipo String. Esto se ha determinado as´ı para facilitar el uso de los programas para los estudiantes. En un ´area de texto en la ventana de cada programa, se tiene una lista con los comandos que el estudiante ha utilizado durante la sesi´on de trabajo. Los comandos que all´ı aparecen son los que llevaron la estructura de datos al
36
CAP´ITULO 3. SOFTWARE INTERACTIVO
estado actual. Esta lista de comandos tambi´en se almacena en un archivo de texto plano, con el historial de comandos. Este archivo puede ser le´ıdo en cualquier editor de textos. Las instrucciones escritas en el historial de comandos podr´ıan ser utilizadas por el estudiante para construir un programa en Java y tendr´ıa el mismo efecto. La u ´nica diferencia ser´ıa la parte visual. El docente puede tomar estos archivos de historial con el fin de hacer seguimiento a los estudiantes. El estudiante tambi´en puede guardar las estructuras de datos que va creando. Puede utilizar los archivos de historial para hacer pruebas manuales con la secuencia de comandos y comparar el resultado de su prueba de escritorio con el estado de la estructura almacenada la cual puede ver en la pantalla y no se la tiene que imaginar. Por otra parte, estos programas interactivos pueden ser utilizados antes de iniciar la explicaci´on te´orica de las estructuras de datos, porque para entenderlos no es necesario saber programar. Algunas caracter´ısticas comunes a los programas interactivos son: El men´ u comprende casi la totalidad de los m´etodos de cada librer´ıa, excepto los m´etodos que se llaman autom´aticamente para mostrar resultados en un ´area de texto en la ventana. El indicador de cambios. Un c´ırculo de color verde indica que la estructura no ha cambiado desde que se almacen´o en disco. Si el c´ırculo se encuentra en rojo, indica que la estructura debe ser almacenada en disco. El programa interativo controla las situaciones en las cuales algunos de los m´etodos no pueden ser llamados y controla tambi´en el paso de informaci´on a los m´etodos que se solicitan. Este control se realiza a trav´es de mensajes de error, producto de un detallado manejo de excepciones. Aunque las librer´ıas de clase son muy poderosas y permiten el uso de cualquier tipo de datos, el software interactivo solo permite el uso de cadenas (objetos de la clase String).
37 Uso de extensiones personalizadas para cada una de las diez estructuras de datos y filtros que facilitan el uso de las opciones abrir y guardar. A continuaci´on se pueden apreciar algunos aspectos comunes a los programas interactivos de lista sencillamente enlazada, lista doblemente enlazada, lista circular sencillamente enlazada y lista circular doblemente enlazada. Ver figura 3.1.
Figura 3.1: Apariencia de los programas interactivos de listas, cola y pila En la imagen se puede observar que el estado de la lista se escribe en modo texto y se visualiza en la parte derecha de la ventana. En esta ´area se puede destacar que el nodo actual se presenta de color rojo. Hay un ´area de la ventana destinada a la informaci´on del nodo actual. Finalmente se tiene reservado un espacio para el u ´ltimo comando. Sin embargo, si se utilizan las flechas de scroll, se pueden ver las l´ıneas de c´odigo Java que han sido ejecutadas a trav´es de los clics de rat´on que ha realizado el usuario. Es importante destacar que el ´area de visualizaci´on es din´amica, es decir, si se produce un cambio en la lista, inmediatamente se ve reflejado en el ´area de visualizaci´on. Igual ocurre si se adiciona un nodo, si se elimina, si se cambia la informaci´on del campo de datos o si modifica la posici´on del nodo actual. Incluso el usuario puede cambiar la posici´on del nodo actual haciendo clic en el nodo que desee en la zona de visualizaci´on. En la figura 3.2 se pueden apreciar los comandos que ofrecen los programas interactivos de listas. Estos comandos son comunes a las cuatro clases de listas que componen el paquete.
38
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.2: Men´ u de los programas interactivos de listas
La apariencia de la ventana en los programas interactivos de cola y pila es muy similar a la apariencia de la ventana en los programas de listas. En el programa interactivo de cola y pila, el usuario no puede cambiar la posici´on del nodo actual porque esa funcionalidad no la ofrece la librer´ıa. En las figuras 3.3 y 3.4 se pueden apreciar los comandos que ofrecen los programas interactivos de cola y pila.
Figura 3.3: Men´ us del programa interactivo de cola
Figura 3.4: Men´ us del programa interactivo de pila A continuaci´on se pueden apreciar algunos aspectos comunes a los programas interactivos de ´arbol n-ario y ´arbol binario. Ver figura 3.5.
39
Figura 3.5: Apariencia de los programas interactivos de ´arboles En la imagen se pueden ver las partes de la ventana de los programas interactivos de ´arbol n-ario y ´abol binario. En ella se puede resaltar la zona de visualizaci´on del ´arbol. En ella se puede ver el ´arbol completamente expandido y el nodo actual presentadodo de color rojo. El usuario puede cambiar el nodo actual haciendo clic en el nodo que desee. Tambi´en se puede ver cuando uno de los hijos es nulo. Se tiene un ´area especial para mostrar la informaci´on del ´arbol y del nodo actual. Al igual que en el caso de las listas, en la ventana del programa interactivo de ´arbol n-ario o ´arbol binario, se pueden ver los comandos que el usuario ha utilizado, traducidos a lenguaje Java. Un aspecto importante en el caso de los programas interactivos de ´arboles es la presentaci´on de los recorridos preorden, posorden y por niveles. Estos recorridos facilitan la interpretaci´on de la informaci´on del ´arbol y permiten al estudiante practicar estos conceptos. Los recorridos corresponden al ´arbol completo, a pesar de que en las librer´ıas se hace el recorrido a partir del nodo actual. En el caso del ´arbol binario, hay un recorrido adicional, llamado recorrido inorden.
40
CAP´ITULO 3. SOFTWARE INTERACTIVO
En la figura 3.6 se pueden apreciar los comandos que ofrecen los programas interactivos de ´arboles. Estos comandos son comunes a las dos clases de ´arboles que componen el paquete.
Figura 3.6: Men´ u de los programas interactivos de ´arboles A continuaci´on se pueden apreciar algunos aspectos comunes a los programas interactivos de grafo dirigido y grafo no dirigido. Ver figura 3.7.
Figura 3.7: Apariencia de los programas interactivos de grafos En la imagen se pueden ver las partes de la ventana de los programas interactivos de grafo dirigido y grafo no dirigido. En ella se puede destacar la zona donde se presenta el estado del grafo. El estado del grafo consiste en determinar el tama˜ no del grafo (cantidad de nodos), y las conexiones de cada uno de los nodos que compone el grafo, incluyendo el destino en cada
41 puerto de conexi´on y el peso asociado a cada enlace. Se tiene un ´area especial para mostrar la informaci´on de cualquiera de los nodos, de acuerdo con las solicitudes del usuario. Al igual que en el caso de las listas y los ´arboles, en la ventana del programa interactivo de grafo dirigido o grafo no dirigido, se pueden ver los comandos que el usuario ha utilizado, traducidos a lenguaje Java. En la parte derecha, se tiene la zona de visualizaci´on. En ella se pueden ver los ´arboles de expansi´on y los respectivos recorridos, en profundidad y en amplitud, los cuales tienen aplicaci´on cuando se desea analizar el comportamiento del grafo. En estos recorridos es necesario establecer el nodo inicial, el cual se convierte en el nodo ra´ız del ´arbol. Si se modifica el nodo inicial o si se realizan nuevas conexiones o se rompen enlaces, se actualizan los ´arboles de expansi´on, de manera autom´atica. En la figura 3.8 se pueden apreciar los comandos que ofrecen los programas interactivos de grafos. Estos comandos son comunes a las dos clases de grafos que componen el paquete.
Figura 3.8: Men´ u de los programas interactivos de grafos A continuaci´on se pueden apreciar algunas im´agenes de los programas interactivos de listas enlazadas. Ver figuras 3.9 a 3.12.
42
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.9: Programa interactivo de Lista sencillamente enlazada
Figura 3.10: Programa interactivo de Lista doblemente enlazada
43
Figura 3.11: Programa interactivo de Lista circular sencillamente enlazada
Figura 3.12: Programa interactivo de Lista circular doblemente enlazada Las ventanas de entrada de datos en los programas de listas enlazadas son los que se pueden ver en las figuras 3.13 y 3.14.
44
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.13: Entrada del campo de datos de un nodo
Figura 3.14: Entrada de una posici´on en la lista Los programas interactivos de listas generan algunos mensajes de alerta cuando el usuario intenta realizar alguna operaci´on no permitida, como es el caso de intentar ir al primer nodo cuando no hay nodos en la lista, ir al nodo que ocupa una posici´on determinada en la lista cuando dicha posici´on no existe, intentar actualizar un nodo cuando el nodo actual es indeterminado o cuando se pueden perder cambios en la lista si el estado actual de la lista se va a perder porque el usuario va a crear una nueva lista o porque va a salir del programa. Los cuatro programas interactivos de listas presentan los mismos mensajes de alerta en situaciones similares. Ver en las figuras 3.15 a la 3.19.
Figura 3.15: Alerta: No hay nodos en la lista
Figura 3.16: Alerta: Posici´on no v´alida
45
Figura 3.17: Alerta: Nodo actual indeterminado
Figura 3.18: Alerta: Desea inicializar la lista?
Figura 3.19: Alerta: Desea abandonar la lista?
A continuaci´on se pueden apreciar algunas im´agenes del programa interactivo de cola y pila, y los mensajes de entrada y salida. Ver figuras 3.20a la 3.24.
Figura 3.20: Programa interactivo de Cola
46
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.21: Programa interactivo de Pila
Figura 3.22: Entrada del campo de datos de un nodo
Figura 3.23: Buscar un elemento en la cola o en la pila
Figura 3.24: Primer elemento de la cola o la pila Los programas interactivos de cola y pila tambi´en pueden manipular archivos con el contenido de las estructuras de datos. En caso de que el estado actual de la cola o la pila no se encuentre debidamente almacenado en disco, se
47 obtienen en pantalla los mensajes de alerta similares a los de los programas interactivos de listas enlazadas, en las figuras 3.18 y 3.19. A continuaci´on se pueden apreciar algunas im´agenes de los programas interactivos de ´arboles. Ver figuras 3.25 y 3.26.
´ Figura 3.25: Programa interactivo de Arbol n-ario
48
CAP´ITULO 3. SOFTWARE INTERACTIVO
´ Figura 3.26: Programa interactivo de Arbol binario Los programas interactivos de ´arboles presentan las siguientes ventanas de entrada de datos. Ver figuras 3.27 a la 3.32.
Figura 3.27: Entrada del nodo ra´ız
Figura 3.28: Entrada de un hijo en ´arbol n-ario
49
Figura 3.29: Entrada de un hijo en ´arbol binario
Figura 3.30: Entrada del campo de datos de un nodo
Figura 3.31: Ir a un hijo en ´arbol n-ario
Figura 3.32: Ir a un hijo en ´arbol binario Los programas interactivos de ´arboles presentan algunos mensajes de error cuando el usuario intenta realizar acciones no permitidas. Ver figuras 3.33 y 3.34.
50
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.33: Alerta: Operaci´on no permitida
Figura 3.34: Alerta: No existe el hijo especificado
A continuaci´on se pueden apreciar algunas im´agenes de los programas interactivos de grafo dirigido y grafo no dirigido. Ver figuras 3.35 y 3.36.
Figura 3.35: Programa interactivo de Grafo dirigido
51
Figura 3.36: Programa interactivo de Grafo no dirigido Para la entrada de datos del usuario en los programas interactivos de grafos, se presentan ventanas de di´alogo, las cuales se pueden ver en las figuras 3.37 a la 3.46.
Figura 3.37: Adici´on de un nodo al grafo
52
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.38: Eliminar un nodo del grafo
Figura 3.39: Conectar dos nodos a trav´es de un enlace
Figura 3.40: Eliminar un enlace
Figura 3.41: Establecer el peso de un enlace
53
Figura 3.42: Establecer el m´aximo n´ umero de puertos de un nodo
Figura 3.43: Establecer el nodo inicial
Figura 3.44: Obtener el campo de datos de un nodo
Una ventana similar a la de la figura 3.44 se presenta cada vez que el usuario debe determinar el nombre del nodo para obtener alguna informaci´on del nodo seleccionado.
54
CAP´ITULO 3. SOFTWARE INTERACTIVO
Figura 3.45: Buscar un nodo con un campo de datos determinado
Figura 3.46: Determinar el destino de un enlace
Los programas interactivos de grafos presentan algunos mensajes de error cuando el usuario intenta realizar acciones no permitidas. Ver figuras 3.47 y 3.48.
Figura 3.47: Alerta: Ese nombre ya pertenece al grafo
Figura 3.48: Alerta: M´aximo n´ umero de puertos no v´alido
Los programas interactivos de ´arbol n-ario, ´arbol binario, grafo dirigido y grafo no diridigo tambi´en pueden manipular archivos con el contenido de las estructuras de datos. En caso de que el estado actual del ´arbol o del grafo no se encuentre debidamente almacenado en disco, se obtienen en pantalla
55 los mensajes de alerta similares a los de los programas interactivos de listas enlazadas, en las figuras 3.18 y 3.19. Todos los errores que pueden afectar el funcionamiento correcto de cada programa son controlado gracias a la gesti´on de excepciones de cada m´etodo de las diferentes librer´ıas. Sin embargo, en el software interactivo, la interface gr´afica de usuario evita errores, por ejemplo al momento de seleccionar un nodo del grafo, debido a que no le permite hacer al usuario una selecci´on no v´alida. Por otra parte, en la opci´on de Ayuda - Acerca de se puede apreciar la ventana en la cual se muestran los datos del autor y la Universidad del Quind´ıo. Todos los programas interactivos tienen la misma ventana de cr´editos, pero cada uno tiene su correspondiente t´ıtulo. Ver figura 3.49.
Figura 3.49: Ventana de Cr´editos
Finalmente, cuando se termina la ejecuci´on del programa interactivo de estructuras de datos se crea un archivo de historial. Este archivo tiene un nombre predeterminado y si el usuario ejecuta de nuevo el programa, se sobreescribe para evitar que se acumulen muchos archivos. Si se desea salvar el archivo de historial, es necesario copiarlo en otra carpeta o cambiarle el nombre. A continuaci´on se presenta la lista con los nombres de los archivos de historial para cada uno de los programas interactivos.
CAP´ITULO 3. SOFTWARE INTERACTIVO
56
Programa interactivo LSEInteractivo.jar LDEInteractivo.jar LCSEInteractivo.jar LCDEInteractivo.jar ColaInteractivo.jar ColaInteractivo.jar ANInteractivo.jar ABInteractivo.jar GDInteractivo.jar GNDInteractivo.jar
Nombre archivo de historial Historial.sl.txt Historial.dl.txt Historial.csl.txt Historial.cdl.txt Historial.que.txt Historial.stk.txt Historial.nt.txt Historial.bt.txt Historial.dg.txt Historial.ug.txt
Un ejemplo de lo que se puede almacenar en el archivo Historial.nt.txt se puede ver a continuaci´on. // Tree arbol; // arbol = new Tree ( ); arbol.addRoot arbol.addSon arbol.goParent arbol.addSon arbol.addSon arbol.goParent arbol.addSon arbol.goRoot arbol.goSon arbol.addSon arbol.removeLeaf arbol.removeSubTree arbol.addSon
( ( ( ( ( ( ( ( ( ( ( ( (
"a" ); "b", 3 ); "c", 1 "d", 2 ); "c", 3 ); 1 ); "f", 4 ); ); "t", 1
); ); ); );
);
);
//arbol.setCurrent ( --- ); //el actual ahora es: d arbol.addSon arbol.save arbol.newTree arbol =
( ( ( (
"y", 2 ); "prueba.nt" ); ); Tree ) Tree.load ( "prueba.nt" );
Archivo generado por ... Curso Interactivo de Estructuras de Datos --- Carlos E. Gomez M. - Uniquindio 2004 Noviembre 6 de 2004 - 4:59 pm
Parte III Documentaci´ on detallada
57
4
Nodos y enlaces Una estructura de datos es una colecci´on de datos, no siempre del mismo tipo, los cuales se relacionan entre s´ı y pueden funcionar como una sola unidad. Las estructuras de datos se pueden dise˜ nar a partir de la combinaci´on adecuada de nodos y enlaces. Un nodo es un elemento que puede almacenar cualquier tipo de informaci´on. Es m´as, en un nodo se puede almacenar informaci´on de un tipo y en otro nodo, almacenar informaci´on de otro tipo.
4.1.
Componentes de un Nodo
En un nodo se pueden destacar los siguientes atributos: data: Es el campo de datos. En este campo se almacena una referencia a un dato de tipo Object, es decir, cualquier objeto en Java. name: Es el nombre del nodo, almacenado en una variable de tipo String. numberInputLinks: Es un entero que almacena el n´ umero de conexiones entrantes.
60
CAP´ITULO 4. NODOS Y ENLACES maxPort: Es un entero que permite controlar el n´ umero m´aximo de puertos que se le permite tener al nodo. Si este n´ umero es 0 (cero), quiere decir que no se tiene restricci´on alguna en este aspecto. port: Es un vector din´amico de puertos con los que este nodo puede establecer conexi´on. En cada puerto se origina un enlace unidireccional. Es posible utilizar el n´ umero de puertos que el usuario desee, siempre y cuando lo permita el campo maxPort. flag: Es un valor de tipo boolean el cual ser´a utilizado para marcar un nodo cuando sea necesario, por ejemplo, si el nodo hacer parte de un grafo, puede ser marcado cuando es visitado. Un enlace es un objeto que permite enlazar o conectar un nodo con otro. Un puerto est´a compuesto por tres campos: • target: Es el nodo destino del enlace. • weight: Es un dato de tipo double que almacena el peso del enlace. • backPort: Es el n´ umero del puerto utilizado para la conexi´on en sentido contrario, reservado especialmente para utilizarlo en los grafos no dirigidos. El valor -1 permanece por omisi´on y normalmente no es utilizado en otras aplicaciones.
Se debe tener en cuenta que la numeraci´on de los ´ındices inicia en 0. Ver figuras 4.1 y 4.2.
Figura 4.1: Nodo
4.2. OPERACIONES DE UN NODO
61
Figura 4.2: Enlace
4.2.
Operaciones de un nodo
Las operaciones a realizar sobre un nodo se pueden clasificar de la siguiente manera: Construcci´ on: Establece un nodo con un vector de puertos de tama˜ no 1. Existen cuatro formas de inicializar un nodo: 1. Sin par´ametros, establece cero en el campo maxPort y el nombre por omisi´on ("noName"). 2. Con un par´ametro que especifica el nombre del nodo, estableciendo cero en el campo maxPort. 3. Con un par´ametro que especifica el el campo maxPort y el nombre por omisi´on ("noName"). 4. Con dos par´ametros, especificando el nuevo valor para el campo maxPort y el nombre del nodo. Modificaci´ on: Operaciones que modifican un nodo. Se tienen seis operaciones modificadoras: 1. set: Establece o reasigna la referencia al objeto que se almacena en el campo de datos del nodo. 2. setName: Establece o reasigna el nombre del nodo. 3. setMaxPort: Establece o reasigna el valor del n´ umero m´aximo de puertos del nodo. Si existe alguna restricci´on en el n´ umero de puertos, es posible retirarla (asignar cero), o aumentar el n´ umero de puertos permitido. 4. setWeight: Establece o reasigna el valor del peso asociado a uno de los puertos de conexi´on.
62
CAP´ITULO 4. NODOS Y ENLACES 5. link: Establece una conexi´on entre un nodo y otro. Para realizar esta conexi´on es necesario especificar el n´ umero del puerto. El valor del peso del enlace puede ser especificado o si se desea, se asigna el peso por omisi´on (1.0). 6. unLink: Desconecta un puerto especificado de un nodo, es decir, elimina una conexi´on. 7. setFlag: Establece o reasigna el valor el atributo flag. 8. less: Es un m´etodo que se utiliza para disminuir en una unidad el valor almacenado en el atributo getNumberInputLinks. 9. plus: Es un m´etodo que se utiliza para aumentar en una unidad el valor almacenado en el atributo getNumberInputLinks. An´ alisis: Son operaciones que permiten obtener informaci´on del nodo. Existen 14 operaciones analizadoras: 1. get: Permite obtener la referencia al objeto almacenado en el campo de datos del nodo. 2. getName: Retorna el valor almacenado en el campo name. 3. getNumberInputLinks: Retorna el valor almacenado en el campo numberInputLinks. 4. getMaxPort: Retorna el valor almacenado en el campo maxPort. 5. getSize: Retorna el n´ umero de puertos del vector de puertos del nodo. 6. getLink: Retorna el objeto de tipo Link (puerto), para poder manipularlo. Es necesario especificar el ´ındice del puerto dentro del vector de puertos del nodo. 7. getWeight: Retorna el valor del peso almacenado en el puerto especificado. 8. getLeastNumberPort: Retorna el n´ umero entero que corresponde al menor puerto libre del nodo. En caso de no tener ning´ un puerto libre, retorna el n´ umero del siguiente puerto que puede ser creado para realizar una conexi´on. 9. getOutputLinks: Retorna una cadena donde se especifican los nodos directamente conectados con el nodo, indicando el n´ umero del puerto utilizado para cada conexi´on.
4.3. DETALLES DE LAS OPERACIONES
63
10. getFlag: Retorna el valor del atributo flag. 11. isData: Retorna un valor boolean que indica si el campo de datos es diferente de null o no. 12. isLink: Retorna un valor boolean que indica si el puerto especificado est´a conectado o no. 13. search: Retorna un n´ umero entero que indica el n´ umero del puerto utilizado en una conexi´on cuyo destino tiene un campo de datos igual al especificado. 14. whoLink: Retorna una referencia al nodo que se encuentra conectado en el puerto especificado. 15. toString: Retorna una cadena con el contenido del nodo.
4.3.
Detalles de las operaciones
4.3.1.
Construcci´ on
El objetivo de esta operaci´on es crear un nodo con un vector de puertos de tama˜ no 1. A trav´es de este puerto, el nodo podr´a conectarse con otro nodo. Este puerto tendr´a null como valor inicial. De igual manera, la informaci´on del campo data tambi´en ser´a null. En caso de no ser posible la asignaci´on de la memoria al vector de puertos, se lanza una excepci´on1 que indica que no hay memoria para enlazar el nodo con otros nodos. Existen cuatro formas de crear un nodo: Sin especificar ning´ un par´ametro. En este caso, el nombre ser´a asignado por omisi´on ("noName"), al igual que el campo maxPort, en cero, es decir, sin restricci´on alguna. Ver figura 4.3.
1
Una excepci´on es una condici´on anormal que surge en una secuencia de c´odigo en tiempo de ejecuci´on. En otras palabras, es un error en tiempo de ejecuci´on. La gesti´on de excepciones de Java evita problemas e incorpora el manejo de errores en tiempo de ejecuci´on. El control de excepciones es una de las caracter´ısticas de la programaci´on orientada a objetos.
64
CAP´ITULO 4. NODOS Y ENLACES
Figura 4.3: Operaci´on de Construcci´on - 1
Especificando el nombre del nodo. En este caso el campo maxPort inicia en cero, es decir, sin restricci´on alguna. En el siguiente ejemplo, se asigna el nombre "a". Ver figura 4.4.
Figura 4.4: Operaci´on de Construcci´on - 2
Especificando el n´ umero m´aximo de puertos permitido. El nombre del nodo ser´a asignado por omisi´on ("noName"). Ver figura 4.5.
Figura 4.5: Operaci´on de Construcci´on - 3
Especificando el n´ umero m´aximo de puertos permitido y el nombre del nodo. En la figura 4.6 se puede ver un nodo que inicia con un m´aximo de 3 puertos y con el nombre "a".
Figura 4.6: Operaci´on de Construcci´on - 4
4.3. DETALLES DE LAS OPERACIONES
4.3.2.
65
Modificaci´ on
Son operaciones que modifican un nodo, ya sea por la asignaci´on del campo data, asignar un nombre, asignar un peso, asignar un enlace a un puerto, desconectar un puerto, o por asignar el n´ umero m´aximo permitido de puertos del nodo. set Recibe por par´ametro un objeto y lo asigna al campo data. Por ejemplo, puede llegar por par´ametro un objeto de tipo Integer cuyo contenido sea el n´ umero 100. Vea una posible precondici´on en la figura 4.7.
Figura 4.7: set - Precondici´on Al realizar la asignaci´on, lo que realmente ocurre se puede ver en la figura 4.8.
Figura 4.8: set - Poscondici´on - 1
Sin embargo, para facilitar la interpretaci´on de este documento, los diagramas que representen los nodos se van a simplificar y ser´an como el de la figura 4.9.
Figura 4.9: set - Poscondici´on - 2
66
CAP´ITULO 4. NODOS Y ENLACES
Nota importante: En caso de que el valor del campo data ya estuviera asignado, simplemente se sobreescribe la referencia almacenada, quedando almacenado en el nodo el nuevo dato. Esta operaci´on no altera para nada los otros campos del nodo. setName Recibe por par´ametro una cadena y la asigna al campo name. Vea una posible precondici´on en la figura 4.10.
Figura 4.10: setName - Precondici´on La poscondici´on correspondiente donde se asigna el nombre "c" como nuevo nombre al nodo se puede ver en la figura 4.11.
Figura 4.11: setName - Poscondici´on
setMaxPort Recibe por par´ametro un entero y lo asigna al campo maxPort. En caso de que el n´ umero m´aximo de puertos permitido sea cero, se considera que no hay restricci´on. Vea una posible precondici´on en la figura 4.12 donde el valor del campo maxPort es 1. Si se va a aumentar la restricci´on, se lanza una excepci´on.
4.3. DETALLES DE LAS OPERACIONES
67
Figura 4.12: setMaxPort - Precondici´on
La poscondici´on correspondiente donde se asigna un 2 se puede ver en la figura 4.13.
Figura 4.13: setMaxPort - Poscondici´on
setWeight Recibe por par´ametro el n´ umero de puerto y el peso que se debe asignar. Vea una posible precondici´on en la figura 4.14. Si el vector de puertos del nodo no tiene la posici´on especificada en el n´ umero de puerto o est´a desconectado el puerto, se lanza una excepci´on.
Figura 4.14: setWeight - Precondici´on
CAP´ITULO 4. NODOS Y ENLACES
68
La poscondici´on correspondiente donde se asigna al nodo E un valor de 2.5 al puerto 4 se puede ver en la figura 4.15.
Figura 4.15: setWeight - Poscondici´on
link Conecta un nodo con otro en el puerto indicado. Existen dos posibilidades: Con tres par´ametros: La referencia al nodo con el que se debe conectar, el n´ umero del puerto que debe utilizar para realizar esa conexi´on y el peso del enlace. Los puertos se cuentan a partir del puerto n´ umero cero (0). Si el n´ umero del puerto corresponde a uno de los puertos existentes, simplemente lo sobreescribe (cambia su valor, sin importar si estaba libre o ocupado). En caso de que el n´ umero del puerto sea negativo, se dispara una excepci´on, pero si el n´ umero del puerto es positivo y no corresponde a uno existente, se ajusta el n´ umero de puertos de manera autom´atica para realizar la conexi´on. Los puertos que se crean son inicializados con valor null. La conexi´on entre dos nodos se puede ver en la figura 4.16.
4.3. DETALLES DE LAS OPERACIONES
69
Figura 4.16: link - Conexi´on de dos nodos - 1 Con el fin de hacer que los diagramas sean m´as f´aciles de entender, asumiremos que los diagramas de la figuras 4.16 y 4.17 son equivalentes.
Figura 4.17: link - Conexi´on de dos nodos - 2 Por ejemplo, considere la figura 4.18 como precondici´on, en la cual se omitieron los pesos de los enlaces para descongestionar la imagen. Suponga que al nodo A le llegan como par´ametros el nodo D, el puerto n´ umero 4 y un peso de 1.2.
Figura 4.18: link ( 1 ) - Precondici´on Como se puede apreciar, el nodo A solo tiene tres puertos (´ındices 0, 1, y 2). Lo primero que ocurre es que el vector de puertos se ajusta en
70
CAP´ITULO 4. NODOS Y ENLACES tama˜ no, es decir, crece a cinco puertos (´ındices 0 a 4). Los dos nuevos nodos son creados con valor null. Ver figura 4.19.
Figura 4.19: link ( 2 ) A continuaci´on, se produce el enlace correspondiente. Ver figura 4.20.
Figura 4.20: link ( 3 )
4.3. DETALLES DE LAS OPERACIONES
71
Luego, se asigna el valor al peso del enlace. Ver figura 4.21.
Figura 4.21: link ( 4 )
Finalmente, se actualiza el valor del atributo numberInputLinks. Ver figura 4.22.
Figura 4.22: link ( 5 ) - Poscondici´on
Es importante tener en cuenta que cuando se sobreescribe un enlace, es necesario disminuir este atributo en el nodo destino existente antes de hacer el enlace.
CAP´ITULO 4. NODOS Y ENLACES
72
Con dos par´ametros: La referencia al nodo con el que se debe conectar y el n´ umero del puerto. El procedimiento es exactamente igual, solo que se asigna el valor del peso por omisi´on (1.0). unLink Desconecta un nodo en el puerto indicado. Recibe como par´ametro el n´ umero del puerto que debe desconectar. Los puertos se cuentan a partir del puerto n´ umero cero (0). Es importante tener en cuenta que si el n´ umero del puerto est´a por fuera de los l´ımites del vector de puertos, se lanza una excepci´on por n´ umero de puerto no v´alido. En caso de que sea posible desconectar el nodo, simplemente se hace una conexi´on del puerto hacia null y se actualiza el campo numberInputLinks. Por ejemplo, considere la figura 4.23 como precondici´on. Suponga que al nodo B le llega por par´ametro el n´ umero 1 como n´ umero de puerto.
Figura 4.23: unLink ( 1 ) - Precondici´on Se actualiza el campo numberInputLinks en el nodo destino, en este caso en el nodo A. Ver figura 4.24.
4.3. DETALLES DE LAS OPERACIONES
73
Figura 4.24: unLink ( 2 ) - Poscondici´on
Se desconecta el puerto. Ver figura 4.25.
Figura 4.25: unLink ( 3 )
less Es un m´etodo que se utiliza para disminuir en una unidad el valor almacenado en el atributo getNumberInputLinks.
CAP´ITULO 4. NODOS Y ENLACES
74 plus
Es un m´etodo que se utiliza para aumentar en una unidad el valor almacenado en el atributo getNumberInputLinks. setFlag Establece o reasigna el valor el atributo flag.
4.3.3.
An´ alisis
Son operaciones que permiten obtener informaci´on de un nodo, como por ejemplo, recuperar la referencia al objeto almacenado en el campo data, saber si la informaci´on almacenada en el nodo es v´alida, saber si un puerto del nodo est´a enlazado o no, conocer con qui´en est´a enlazado un nodo en un puerto determinado, conocer el n´ umero de puertos del nodo y ense˜ narle al nodo la forma como debe presentar la informaci´on cuando sea requerida, entre otras. get No recibe ning´ un par´ametro. Devuelve el contenido del campo data. Por ejemplo, de acuerdo con la figura 4.26, la operaci´on get, retorna una referencia a un objeto de tipo Integer cuyo contenido en el n´ umero entero 1. Es responsabilidad del usuario verificar con anticipaci´on si hay informaci´on en el nodo o no.
Figura 4.26: get
getName No recibe ning´ un par´ametro. Devuelve el contenido del campo name. Por ejemplo, de acuerdo con la figura 4.27, la operaci´on getName, retorna una cadena con el nombre del nodo, en este caso "e".
4.3. DETALLES DE LAS OPERACIONES
75
Figura 4.27: getName
getNumberInputLinks Devuelve el contenido del campo numberInputLinks. No recibe ning´ un par´ametro. Por ejemplo, la operaci´on getNumberInputLinks, de acuerdo con la figura 4.28, retorna un 2 que corresponde al n´ umero de conexiones externas que tiene el nodo.
Figura 4.28: getNumberInputlinks
getMaxPort No recibe ning´ un par´ametro. Devuelve el contenido del campo maxPort. Por ejemplo, de acuerdo con la figura 4.29, la operaci´on getMaxPort, retorna un 3 que corresponde al n´ umero m´aximo de puertos permitido.
Figura 4.29: getMaxPort
getSize No recibe ning´ un par´ametro. Devuelve el n´ umero de puertos del nodo. Por ejemplo, si en la figura 4.30 se le aplica esta operaci´on al nodo A retorna 3, si se le aplica al nodo B retorna 5.
76
CAP´ITULO 4. NODOS Y ENLACES
Figura 4.30: getSize
getLink Recibe por par´ametro el n´ umero del enlace que se desea obtener. Retorna el enlace como objeto para manipularlo, ya sea que se necesite asignar el peso o el n´ umero de puerto utilizado en una conexi´on en sentido contrario. Por ejemplo, de acuerdo con la figura 4.31, la operaci´on getLink, retorna el enlace con ´ındice especificado.
Figura 4.31: getLink - 1 La figura 4.31 es equivalente a la figura 4.32.
4.3. DETALLES DE LAS OPERACIONES
77
Figura 4.32: getLink - 2 Lo que se obtiene es el enlace. Ver figura 4.33.
Figura 4.33: getLink - 3
getWeight Recibe por par´ametro el n´ umero de puerto del cual desea obtener el peso. Devuelve un dato de tipo double. Por ejemplo, si en la figura 4.34 se le aplica esta operaci´on al nodo en el puerto 0, retorna 2.1.
Figura 4.34: getWeight
getLeastNumberPort No recibe ning´ un par´ametro. Devuelve un entero que indica el n´ umero de puerto libre con ´ındice menor. Por ejemplo, de acuerdo con la figura 4.35, la operaci´on getLeastNumberPort, aplicada sobre el nodo A, retorna 3 (el puerto no existe pero no hay ninguno disponible). De igual manera, si se le aplica al nodo E, retorna 1.
CAP´ITULO 4. NODOS Y ENLACES
78
Figura 4.35: getLeastNumberPort
getOutputLinks No recibe ning´ un par´ametro. Devuelve una cadena que permite identificar las conexiones directas del nodo en cada uno de los puertos. Ver figura 4.36.
Figura 4.36: getDirectedLinked
De acuerdo con la figura 4.36, la operaci´on getOutputLinks, aplicada sobre el nodo A retorna, en forma de cadena: 0: b { 2 } - [ 2.3 ] 1: null
4.3. DETALLES DE LAS OPERACIONES
79
2: null 3: c { 4 } - [ 3.5 ] Al interpretar la cadena se deduce f´acilmente que el nodo A est´a conectado en el puerto 0 con el nodo B cuyo contenido es 2 y con un peso de 2.3; tiene null en los puertos 1 y 2, y que est´a conectado con el nodo C en el puerto 3, con contenido 4 y un peso en el enlace de 3.5. getFlag Retorna el valor del atributo flag. isData No recibe ning´ un par´ametro. Retorna un true o false indicando si el campo data ha sido inicializado o no. Por ejemplo, si en figura 4.37 se le aplica esta operaci´on al nodo D retorna un true, pero si se le aplica al nodo E retorna un false.
Figura 4.37: isData
isLink Recibe por par´ametro el n´ umero del puerto que se desea verificar. Devuelve true o false indicando si el puerto est´a enlazado o no. Es importante tener
80
CAP´ITULO 4. NODOS Y ENLACES
en cuenta que la numeraci´on de los puertos del nodo inicia a partir de 0. Por ejemplo, si en la figura 4.38 se le aplica esta operaci´on al nodo C en el puerto 2 retorna false, pero si se le aplica al nodo B en el puerto 4 retorna un true. Este m´etodo lanza una excepci´on en caso de que el n´ umero de puerto no sea v´alido.
Figura 4.38: isLink
search Permite encontrar el n´ umero de puerto utilizado para una conexi´on con un nodo cuyo campo de datos coincide con la referencia a un objeto igual al que se recibe por par´ametro. Retorna el n´ umero de puerto de la primera coincidencia. Por ejemplo, en la precondici´on de la figura 4.39 se le aplica la operaci´on search al nodo A, buscando una conexi´on con un objeto de tipo Integer cuyo contenido sea un n´ umero 4 retorna el 1 como n´ umero de puerto. En caso de no encontrar lo que est´a buscando, retorna -1.
4.3. DETALLES DE LAS OPERACIONES
81
Figura 4.39: search
whoLink Recibe por par´ametro el n´ umero del puerto del cual se desea conocer el destinatario del enlace. Devuelve una referencia a ese nodo. Esta es una operaci´on que permite navegar por la estructura de datos. Por ejemplo, si en la figura 4.40 se le aplica esta operaci´on al nodo A en el puerto 1 retorna una referencia al nodo C, si se le aplica al nodo D en el puerto 0 retorna una referencia al nodo B, o retorna null si se le aplica al nodo C en el puerto 1. Recuerde que la numeraci´on de los puertos del nodo inicia a partir de 0. En caso de que el n´ umero del puerto no haga parte del vector de puertos del nodo, se lanza una excepci´on.
82
CAP´ITULO 4. NODOS Y ENLACES
Figura 4.40: whoLink
toString El prop´osito de esta operaci´on es ense˜ narle al nodo a imprimirse, en forma de cadena (String en Java), cuando se necesite su informaci´on. Por ejemplo, si en la figura 4.41 se le aplica esta operaci´on al nodo C retorna una cadena con los datos (nombre y estatura), acompa˜ nados de sus respectivas etiquetas.
Figura 4.41: toString
5 Lista
La lista es una estructura de datos lineal. Los datos pueden estar organizados en la memoria en posiciones contiguas o en posiciones de memoria no adyacentes (listas enlazadas). Cada elemento de la lista es un nodo1 . En cada nodo se almacena una referencia a un objeto el cual puede ser de cualquier tipo de datos. Esto permite tener nodos de tipos de datos diferentes (cada nodo es independiente a los dem´as). Entre las clases de listas enlazadas m´as frecuentemente utilizadas se encuentran: Lista sencillamente enlazada: Es una lista en la cual cada nodo tiene una conexi´on con un nodo hacia adelante. Ver figura 5.1.
1
Ver Nodos y enlaces.
84
CAP´ITULO 5. LISTA
Figura 5.1: Lista sencillamente enlazada
Lista circular sencillamente enlazada: Es una lista sencillamente enlazada en la cual el siguiente nodo del u ´ltimo nodo de la lista es el primer nodo. Ver figura 5.2.
Figura 5.2: Lista circular sencillmente enlazada
Lista doblemente enlazada: Es una lista en la cual cada nodo tiene una conexi´on con un nodo hacia adelante y otra conexi´on con un nodo hacia atr´as. Ver figura 5.3.
Figura 5.3: Lista doblemente enlazada
Lista circular doblemente enlazada: Es una lista doblemente enlazada en la cual se tienen conectados los nodos inicial y final, de manera que el siguiente del u ´ltimo nodo de la lista es el primer nodo y el anterior al primer nodo de la lista es el u ´ltimo. Ver figura 5.4.
5.1. LISTA DOBLEMENTE ENLAZADA: CONCEPTOS
85
Figura 5.4: Lista circular doblemente enlazada
Este cap´ıtulo trata sobre la lista doblemente enlazada. Todos los conceptos y operaciones son aplicables a los otros tipos de listas mencionados, con algunas ligeras modificaciones para facilitar la construcci´on de la estructura de datos deseada.
5.1.
Lista doblemente enlazada: Conceptos
Cada nodo de la lista doblemente enlazada que se propone en este documento se compone de varios elementos, entre los cuales se destacan dos: data: Campo de datos del nodo. Es una referencia a un objeto gen´erico (dato de tipo Object en Java). port: Es un vector de puertos con los cuales se puede enlazar el nodo con otros nodos. Es un dato de tipo Vector de Java que corresponde a un vector din´amico de objetos. Este vector tiene dos posiciones para enlazarlo hacia el nodo anterior y el nodo siguiente. Ver figura 5.5.
Figura 5.5: Nodo - 1
Los otros campos de un nodo no ser´an utilizados en este documento, por lo tanto, los nodos ser´an como el de la figura 5.6.
CAP´ITULO 5. LISTA
86
Figura 5.6: Nodo - 2
Observe que se asocian los puertos 0 y 1 con dos constantes llamadas BACK y NEXT respectivamente. Esto con el fin de que sea m´as f´acil de recordar los puertos Anterior y Siguiente y evitar confusiones. La lista doblemente enlazada, vista como una unidad, tiene tres referencias a nodos, las cuales se utilizan para controlar la lista completamente, un campo entero para indicar la longitud o tama˜ no de la lista y un campo de tipo boolean que indica si la lista ha sido modificada o no despu´es de la u ´ltima vez que se ha almacenado en disco. En este trabajo, los atributos para cualquier tipo de lista son: first: Referencia al primer nodo current: Referencia al nodo actual last: Referencia al u ´ltimo nodo length: Valor de tipo int que almacena la cantidad de nodos changed: Permite saber si se han presentado cambios en la lista. Muy u ´til para mantener una copia de la lista en disco. En la figura 5.7 se puede apreciar un ejemplo de una lista doblemente enlazada. En ella se pueden apreciar las referencias first, last y current. Observe que el campo de datos puede referenciar objetos de diferente tipo, incluso puede tenerse una referencia null, es decir, sin referenciar ning´ un objeto.
5.1. LISTA DOBLEMENTE ENLAZADA: CONCEPTOS
87
Figura 5.7: Lista doblemente enlazada - 1
En la imagen se ven muchas flechas, cada una con un significado importante. Sin embargo, para facilitar la interpretaci´on de los diagramas de este documento, es mejor que los nodos y la lista se vean como en las figuras 5.8 y 5.9.
Figura 5.8: Nodo - 3
Recuerde que los valores constantes BACK y NEXT corresponden a los n´ umeros de los puertos de cada nodo.
Figura 5.9: Lista doblemente enlazada - 2
CAP´ITULO 5. LISTA
88
Ahora, con el fin de resumir a´ un m´as los gr´aficos de este documento, se van a utilizar diagramas en los cuales se dibuja el contenido del objeto referenciado dentro del nodo. Debe entenderse siempre que se trata de una referencia a un objeto. Ver figura 5.10.
Figura 5.10: Lista doblemente enlazada - 3
5.2.
Operaciones de una lista
Las operaciones a realizar sobre una lista doblemente enlazada se pueden clasificar de la siguiente manera: Construcci´ on: Establece una lista vac´ıa. Modificaci´ on: Operaciones que modifican la lista en su n´ umero de nodos o el contenido de alguno de ellos. Se tienen seis operaciones modificadoras: 1. newList: Establece una lista en su estado inicial, es decir, destruye la lista actual (si existe) y crea una lista vac´ıa. 2. add: Permite adicionar un nodo al final de la lista. 3. update: Permite modificar el campo de datos del nodo actual. 4. insertLeft: Permite insertar un nodo a la izquierda del nodo actual. 5. insertRight: Permite insertar un nodo a la derecha del nodo actual. 6. remove: Permite eliminar el nodo actual.
5.2. OPERACIONES DE UNA LISTA
89
An´ alisis: Son operaciones que permiten obtener informaci´on de la lista o de alg´ un nodo. Existen ocho operaciones analizadoras: 1. get: Permite obtener la referencia al objeto, almacenada en el campo de datos del nodo actual. 2. getSize: Permite obtener el n´ umero de nodos de la lista, almacenado en el atributo length. 3. getIndex: Permite obtener el ´ındice o posici´on del nodo actual en la lista. 4. isValidCurrent: Permite saber si la referencia current es diferente de null (es v´alida) o no. Retorna true o false. 5. getChanged: Permite obtener el valor del atributo changed. El valor de este atributo cambia autom´aticamente despu´es de usar una operaci´on modificadora. Tambi´en toma su valor inicial si se utiliza la operaci´on de persistencia save. 6. toString: Construye una cadena con el contenido de la lista. Al terminar, la referencia current queda se˜ nalando el mismo nodo que ten´ıa antes de iniciar la operaci´on. Localizaci´ on: Operaciones que permiten modificar la posici´on del nodo actual. Existen seis operaciones localizadoras: 1. goFirst: Ubica al nodo actual en el primer nodo de la lista. 2. goLast: Ubica al nodo actual en el u ´ltimo nodo de la lista. 3. goNext: Ubica al nodo actual en el siguiente nodo. 4. goBack: Ubica al nodo actual en el nodo anterior. 5. goTo: Ubica al nodo actual en el nodo de la posici´on especificada. El ´ındice del primer nodo de la lista es 0. Persistencia: Permite almacenar la lista en un archivo o recuperarla. Existen dos operaciones de persistencia: 1. save: Almacena toda la lista en disco, y todos los objetos que sean referenciados por los diferentes nodos que pertenecen a la lista. 2. load: Recupera la lista almacenada en disco, con todos los objetos referenciados por los diferentes nodos de la lista, con el fin de pasarla a memoria.
CAP´ITULO 5. LISTA
90
5.2.1.
Construcci´ on
El objetivo de esta operaci´on es establecer como null las referencias a nodos first, current y last. Tambi´en inicializa en 0 (cero) al atributo length y pone en false al atributo changed. Ver figura 5.11.
Figura 5.11: Construcci´on
5.2.2.
Modificaci´ on
Las operaciones modificadoras permiten hacer cambios en la lista, ya sea porque se aumente o disminuya la cantidad de nodos o porque sea actualizado el contenido de alg´ un nodo. newList Esta operaci´on elimina todos los nodos de la lista, dej´andola vac´ıa. La u ´nica diferencia con el estado inicial es que esta operaci´on deja en true al atributo changed. Una posible precondici´on se puede ver en la figura 5.12.
5.2. OPERACIONES DE UNA LISTA
91
Figura 5.12: newList - Precondici´on Al efectuar esta operaci´on, el resultado es como el de la figura 5.13.
Figura 5.13: newList - Poscondici´on
add Recibe una referencia al objeto, la cual se la va a almacenar en el campo de datos del nuevo nodo. El objetivo es anexar un nodo al final de la lista, es decir, a continuaci´on del u ´ltimo nodo. El nuevo nodo ser´a el nodo actual al terminar la operaci´on. En caso de que la operaci´on de anexar no sea exitosa, se lanza una excepci´on. Se consideran dos casos: lista vac´ıa y lista no vac´ıa. Caso 1. La lista est´a vac´ıa. En este caso, la u ´nica precondici´on posible es la de la figura 5.14.
92
CAP´ITULO 5. LISTA
Figura 5.14: add - Caso 1 - Precondici´on Suponga que se desea anexar un objeto de tipo Character con la letra X en una lista doblemente enlazada. A continuaci´on se pueden ver los pasos que permiten adicionar un nodo a la lista cuando se encuentra vac´ıa. 1. Si no hubo ning´ un problema con la memoria solicitada, se puede contar con un nodo nuevo con dos puertos nulos, listo para ser adicionado a la lista doblemente enlazada. Ver figura 5.15.
Figura 5.15: add - Caso 1 - Paso 1 de 6 2. Se llena el campo de datos del nuevo nodo con la referencia al objeto que contiene la informaci´on. Esta referencia es recibida por par´ametro. Recuerde que el diagrama est´a simplificado. Ver figura 5.16.
5.2. OPERACIONES DE UNA LISTA
Figura 5.16: add - Caso 1 - Paso 2 de 6 3. Ahora first se˜ nala al nuevo nodo. Ver figura 5.17.
Figura 5.17: add - Caso 1 - Paso 3 de 6 4. La referencia last se˜ nala al nuevo nodo. Ver figura 5.18.
Figura 5.18: add - Caso 1 - Paso 4 de 6 5. Luego, current se˜ nala al nuevo nodo. Ver figura 5.19.
93
94
CAP´ITULO 5. LISTA
Figura 5.19: add - Caso 1 - Paso 5 de 6 6. A continuaci´on, se aumenta en una unidad la cantidad de nodos de la lista. Ver figura 5.20.
Figura 5.20: add - Caso 1 - Paso 6 de 6 7. Finalmente, se establece en true el valor del campo changed. Caso 2. Existen nodos en la lista. Cuando la lista no est´a vac´ıa, existen muchas posibles precondiciones. Para este caso, suponga la lista de caracteres de la figura 5.21 y que se desea anexar una referencia a un objeto de tipo Character que contiene la letra X.
Figura 5.21: add - Caso 2 - Precondici´on Observe los pasos que permiten anexar el nodo al final de la lista.
5.2. OPERACIONES DE UNA LISTA
95
1. Si no se presentaron inconvenientes con la memoria solicitada para el nuevo nodo, se puede contar con ´el a partir de este momento para anexarlo al final de la lista. Ver figura 5.22.
Figura 5.22: add - Caso 2 - Paso 1 de 7 2. Se llena el campo de datos del nuevo nodo con la informaci´on recibida por par´ametro. Ver figura 5.23.
Figura 5.23: add - Caso 2 - Paso 2 de 7 3. A continuaci´on se enlaza el nodo referenciado por last con el nuevo nodo en el puerto NEXT. Ver figura 5.24.
Figura 5.24: add - Caso 2 - Paso 3 de 7
96
CAP´ITULO 5. LISTA 4. A continuaci´on se enlaza el nuevo nodo con el nodo referenciado por last en el puerto BACK. Ver figura 5.25.
Figura 5.25: Anexar - Caso 2 - Paso 4 de 7 5. Luego, last se˜ nala al nuevo nodo, porque ahora es el u ´ltimo nodo de la lista. Ver figura 5.26.
Figura 5.26: add - Caso 2 - Paso 5 de 7 6. En un paso similar al anterior, current se˜ nala al nuevo nodo. Ver figura 5.27.
Figura 5.27: add - Caso 2 - Paso 6 de 7 7. Luego se aumenta el n´ umero de nodos de la lista. Ver figura 5.28.
5.2. OPERACIONES DE UNA LISTA
97
Figura 5.28: add - Caso 2 - Paso 7 de 7 8. Finalmente, se establece en true el valor del campo changed. update Recibe una referencia al objeto, la cual va a reemplazar la que se encuentra almacenada en el campo de datos del nodo actual. En caso de que el nodo actual sea null, se lanza una excepci´on. Para este caso, existen muchas posibles precondiciones. Suponga que la lista se encuentra como la de la figura 5.29 y que se desea actualizar (update) el contenido del campo de datos del nodo actual, por una referencia a un objeto de tipo Character cuyo contenido es la letra X.
Figura 5.29: update - Precondici´on Al hacer la operaci´on update, la lista queda como en la figura 5.30.
CAP´ITULO 5. LISTA
98
Figura 5.30: update - Poscondici´on Finalmente, se establece en true el valor del campo changed. insertLeft Recibe una referencia a un objeto, la cual se va a almacenar en el campo de datos del nuevo nodo. El objetivo es insertar un nodo a la izquierda del nodo actual. Al terminar la operaci´on, el nuevo nodo ser´a el nodo actual. En caso de que no se disponga de la memoria solicitada, se lanza una excepci´on. Se consideran dos situaciones: Lista vac´ıa Lista no vac´ıa Cuando se desea insertar un nodo a la izquierda del nodo actual y la lista se encuentra vac´ıa, se procede igual que en el m´etodo add en el caso 1. Ver p´agina 91. Si el nodo actual est´a indeterminado (null), autom´aticamente se˜ nala al primer nodo para insertar un nodo a la izquierda2 . Cuando la lista no est´a vac´ıa, se consideran dos casos: El nodo actual es tambi´en el primer nodo de la lista El nodo actual es otro nodo distinto del primero. Caso 1. Las referencias current y first tienen el mismo valor, las dos se˜ nalan al mismo nodo. En este caso, existen muchas posibles precondiciones. Suponga la lista de la figura 5.31. 2
Por decisi´on arbitraria por parte del autor.
5.2. OPERACIONES DE UNA LISTA
99
Figura 5.31: insertLeft - Caso 1 - Precondici´on
1. Si no se presentaron inconvenientes con la memoria solicitada para el nuevo nodo, se puede contar con ´el a partir de este momento para insertarlo a la izquierda del nodo actual. Ver figura 5.32.
Figura 5.32: insertLeft - Caso 1 - Paso 1 de 7 2. Suponga que desea insertar en la lista una referencia a un objeto de tipo Character cuyo contenido es la letra X. El paso siguiente es establecer el campo de datos del nuevo nodo con la referencia al objeto que se recibe por par´ametro. Ver figura 5.33.
Figura 5.33: insertLeft - Caso 1 - Paso 2 de 7
100
CAP´ITULO 5. LISTA 3. Ahora se debe enlazar el nodo actual con el nuevo nodo en el puerto BACK. Ver figura 5.34.
Figura 5.34: insertLeft - Caso 1 - Paso 3 de 7 4. A continuaci´on se enlaza el nuevo nodo con el actual en el puerto NEXT. Ver figura 5.35.
Figura 5.35: insertLeft - Caso 1 - Paso 4 de 7 5. Luego, current debe se˜ nalar al nuevo nodo. Ver figura 5.36.
Figura 5.36: insertLeft - Caso 1 - Paso 5 de 7 6. De igual manera, el primer nodo debe se˜ nalar al nuevo nodo. Ver figura 5.37.
5.2. OPERACIONES DE UNA LISTA
101
Figura 5.37: insertLeft - Caso 1 - Paso 6 de 7 7. Luego, se aumenta la cantidad de nodos de la lista. Ver figura 5.38.
Figura 5.38: insertLeft - Caso 1 - Paso 7 de 7 8. El u ´ltimo paso es establecer true en el campo changed. Caso 2. La referencia current se˜ nala un nodo diferente al primer nodo de la lista. En este caso, existen muchas posibles precondiciones. Suponga la lista de la figura 5.39 y que se desea insertar en la lista una referencia a un objeto de tipo Character cuyo contenido es la letra X.
102
CAP´ITULO 5. LISTA
Figura 5.39: insertLeft - Caso 2 - Precondici´on
1. Si no se presentaron inconvenientes con la memoria solicitada para el nuevo nodo (newNode), se puede contar con ´el a partir de este momento para insertarlo a la izquierda del nodo actual. Ver figura 5.40.
Figura 5.40: insertLeft - Caso 2 - Paso 1 de 9 2. Usaremos una referencia temporal al nodo que se encuentra conectado a la izquierda del nodo actual, llamada previousCurrent. Ver figura 5.41.
5.2. OPERACIONES DE UNA LISTA
103
Figura 5.41: insertLeft - Caso 2 - Paso 2 de 9 Observe que las referencias previousCurrent y first se˜ nalan al mismo nodo. Sin embargo, fue gracias a que la referencia current se˜ nala al segundo nodo de la lista. De no ser as´ı, esta coincidencia no se dar´ıa. Estos pasos deben permitir insertar un nodo a la izquierda del nodo actual cuando la lista no est´a vac´ıa y el nodo actual se˜ nala un nodo diferente al primero, sin importar la cantidad de nodos de la lista, es decir, estos pasos deben ser igualmente v´alidos si la lista tiene dos, tres o m´as nodos. 3. El paso siguiente es establecer el campo de datos del nuevo nodo con la referencia al objeto que se recibe por par´ametro. Ver figura 5.42.
Figura 5.42: insertLeft - Caso 2 - Paso 3 de 9
4. Luego, se debe conectar el nuevo nodo (newNode) con el nodo actual (current) en el puerto NEXT. Ver figura 5.43.
104
CAP´ITULO 5. LISTA
Figura 5.43: insertLeft - Caso 2 - Paso 4 de 9 5. A continuaci´on, se conecta el nuevo nodo con el temporal (el anterior del actual) (previousCurrent) en el puerto BACK. Ver figura 5.44.
Figura 5.44: insertLeft - Caso 2 - Paso 5 de 9 6. Luego, se conecta el nodo actual con el nuevo en el puerto BACK. Ver figura 5.45.
5.2. OPERACIONES DE UNA LISTA
105
Figura 5.45: insertLeft - Caso 2 - Paso 6 de 9 7. Luego, se conecta el nodo temporal (previousCurrent) con el nuevo en el puerto NEXT. Ver figura 5.46.
Figura 5.46: insertLeft - Caso 2 - Paso 7 de 9 8. Despu´es se actualiza current para se˜ nalar el nuevo nodo. Ver figura 5.47.
Figura 5.47: insertLeft - Caso 2 - Paso 8 de 9
CAP´ITULO 5. LISTA
106
9. Luego, se aumenta el n´ umero de nodos de la lista. Ver figura 5.48.
Figura 5.48: insertLeft - Caso 2 - Paso 9 de 9 10. Finalmente, se establece el valor true en el campo changed. Es de anotar que la referencia temporal previousCurrent no es absolutamente necesaria. Simplemente se utiliz´o para facilitar la programaci´on de esta operaci´on. Al finalizar, esta referencia desaparece de la memoria, es decir, se libera la memoria que ocupa. insertRight Recibe una referencia a un objeto, la cual se va a almacenar en el campo de datos del nuevo nodo. El objetivo es insertar un nodo a la derecha del nodo actual. Al terminar la operaci´on, el nuevo nodo ser´a el nodo actual. En caso de que no se disponga de la memoria solicitada, se lanza una excepci´on. Se consideran dos situaciones: Lista vac´ıa Lista no vac´ıa Cuando se desea insertar un nodo a la derecha del nodo actual y la lista se encuentra vac´ıa, se procede igual que en el m´etodo add en el caso 1. Ver p´agina 91. Si el nodo actual est´a indeterminado (null), autom´aticamente se˜ nala al u ´ltimo nodo para insertar un nodo a la derecha3 . Cuando la lista no est´a vac´ıa, se consideran dos casos: 3
Por decisi´on arbitraria por parte del autor.
5.2. OPERACIONES DE UNA LISTA
107
El nodo actual es tambi´en el u ´ltimo nodo de la lista El nodo actual es otro nodo distinto del u ´ltimo. Caso 1. Cuando se desea insertar un nodo a la derecha del nodo actual estando el nodo actual se˜ nalando al u ´ltimo nodo, se procede igual que en el m´etodo add en el caso 2 (lista no vac´ıa). Ver p´agina 94. Caso 2. La referencia current se˜ nala un nodo diferente al u ´ltimo. En este caso, existen muchas posibles precondiciones. Suponga la lista de la figura 5.49.
Figura 5.49: insertRight - Caso 2 - Precondici´on
1. Si no se presentaron inconvenientes con la memoria solicitada para el nuevo nodo, se puede contar con ´el a partir de este momento para insertarlo a la derecha del nodo actual. Ver figura 5.50.
Figura 5.50: insertRight - Caso 2 - Paso 1 de 9
108
CAP´ITULO 5. LISTA 2. Usaremos una referencia temporal al nodo que se encuentra conectado a la derecha del nodo actual, llamada nextCurrent. Ver figura 5.51.
Figura 5.51: insertRight - Caso 2 - Paso 2 de 9 Observe que las referencias nextCurrent y last se˜ nalan al mismo nodo. Estos pasos deben permitir insertar un nodo a la derecha del nodo actual cuando la lista no est´a vac´ıa y el nodo actual se˜ nala un nodo diferente al u ´ltimo, sin importar la cantidad de nodos de la lista, es decir, estos pasos deben ser igualmente v´alidos si la lista tiene dos, tres o m´as nodos. 3. Suponga que desea insertar en la lista una referencia a un objeto de tipo Character cuyo contenido es la letra X. El paso siguiente es establecer el campo de datos del nuevo nodo con la referencia al objeto que se recibe por par´ametro. Ver figura 5.52.
Figura 5.52: insertRight - Caso 2 - Paso 3 de 9 4. Luego, se debe conectar el nuevo nodo (newNode) con el nodo actual (current) en el puerto BACK. Ver figura 5.53.
5.2. OPERACIONES DE UNA LISTA
109
Figura 5.53: insertRight - Caso 2 - Paso 4 de 9 5. A continuaci´on, se conecta el nuevo nodo con el temporal (el siguiente del actual) en el puerto NEXT. Ver figura 5.54.
Figura 5.54: insertRight - Caso 2 - Paso 5 de 9 6. Luego, se conecta el nodo temporal (siguiente del actual) con el nuevo en el puerto BACK. Ver figura 5.55.
Figura 5.55: insertRight - Caso 2 - Paso 6 de 9
110
CAP´ITULO 5. LISTA 7. Luego, se conecta el nodo actual con el nuevo en el puerto NEXT. Ver figura 5.56.
Figura 5.56: insertRight - Caso 2 - Paso 7 de 9 8. Despu´es se actualiza current para se˜ nalar el nuevo nodo. Ver figura 5.57.
Figura 5.57: insertRight - Caso 2 - Paso 8 de 9 9. Luego, se aumenta el n´ umero de nodos de la lista. Ver figura 5.58.
5.2. OPERACIONES DE UNA LISTA
111
Figura 5.58: insertRight - Caso 2 - Paso 9 de 9 10. Finalmente, es establece en true el valor del campo changed. Es de anotar que la referencia temporal nextCurrent no es absolutamente necesaria. Simplemente se utiliz´o para facilitar la programaci´on de esta operaci´on. Al finalizar, esta referencia desaparece de la memoria, es decir, se libera la memoria que ocupa. remove La operaci´on remove se encarga de eliminar el nodo actual. Despu´es de eliminar el nodo actual, current queda se˜ nalando el siguiente nodo del nodo eliminado. En caso de que el nodo actual sea indeterminado (null), se lanza una excepci´on. Para eliminar un nodo se consideran cuatro casos: Hay un u ´nico nodo El actual es el primer nodo El actual es el u ´ltimo nodo El actual es otro nodo Caso 1. La lista tiene u ´nicamente un nodo, es decir, su longitud es 1. En este caso, hay una sola precondici´on posible, aunque si se tiene en cuenta el contenido del campo de datos, habr´ıan muchas posibles precondiciones. Ver figura 5.59.
112
CAP´ITULO 5. LISTA
Figura 5.59: remove - Caso 1 - Precondici´on
1. Se actualiza first con valor null. Ver figura 5.60.
Figura 5.60: remove - Caso 1 - Paso 1 de 4 2. Se actualiza current con valor null. Ver figura 5.61.
Figura 5.61: remove - Caso 1 - Paso 2 de 4 3. Se actualiza last con valor null. Ver figura 5.62.
5.2. OPERACIONES DE UNA LISTA
113
Figura 5.62: remove - Caso 1 - Paso 3 de 4 Para el caso de lenguajes como Java, un objeto no referenciado es autom´aticamente marcado para que la memoria que ocupa sea liberada por el recolector de basura4 de Java. Ver figura 5.63.
Figura 5.63: remove - Caso 1 - Recolector de basura 4. La cantidad de nodos de la lista se disminuye en una unidad, indicando que la lista ahora es vac´ıa. Ver figura 5.64.
Figura 5.64: remove - Caso 1 - Paso 4 de 4 5. Finalmente, se establece en true el valor del campo changed. Caso 2. La lista tiene m´as de un nodo y el nodo actual se˜ nala al primer nodo de la lista. En este caso, existen muchas posibles precondiciones. Suponga la lista de la figura 5.65. 4
Es el mecanismo de Java utilizado para liberar la memoria que ocupan los objetos que no est´an en uso. Este sistema de reciclaje de memoria se ejecuta peri´odicamente
114
CAP´ITULO 5. LISTA
Figura 5.65: remove - Caso 2 - Precondici´on
1. Usaremos una referencia temporal al nodo que se encuentra conectado a la derecha del nodo actual, llamada nextCurrent. Ver figura 5.66.
Figura 5.66: remove - Caso 2 - Paso 1 de 5 2. Se actualiza el nodo actual, el cual corresponde al siguiente del nodo actual (el temporal). Ver figura 5.67.
Figura 5.67: remove - Caso 2 - Paso 2 de 5 3. Se actualiza el primer nodo, el cual corresponde temporal . Ver figura 5.68.
5.2. OPERACIONES DE UNA LISTA
115
Figura 5.68: remove - Caso 2 - Paso 3 de 5 4. Se desconecta el primer nodo en el puerto BACK. Ver figura 5.69.
Figura 5.69: remove - Caso 2 - Paso 4 de 5 Debido a que no existe ninguna referencia al nodo cuyo contenido es una referencia a un objeto con el caracter ’A’, este nodo es marcado autom´aticamente para que la memoria que ocupa sea liberada por el recolector de basura de Java. Ver figura 5.70.
Figura 5.70: remove - Caso 2 - Recolector de basura 5. Se disminuye en una unidad la cantidad de nodos de la lista. Ver figura 5.71.
116
CAP´ITULO 5. LISTA
Figura 5.71: remove - Caso 2 - Paso 5 de 5 6. Finalmente, se establece en true el campo changed. Caso 3. La lista tiene m´as de un nodo y el nodo actual se˜ nala al u ´ltimo nodo de la lista. En este caso, existen muchas posibles precondiciones. Suponga la lista de la figura 5.72.
Figura 5.72: remove - Caso 3 - Precondici´on
1. Se actualiza last, el cual corresponde al anterior del nodo actual. Ver figura 5.73.
Figura 5.73: remove - Caso 3 - Paso 1 de 4
5.2. OPERACIONES DE UNA LISTA
117
2. Se actualiza current, el cual corresponde al siguiente del nodo actual, es decir, el nodo actual queda con valor null. Ver figura 5.74.
Figura 5.74: remove - Caso 3 - Paso 2 de 4 3. Se desconecta el u ´ltimo nodo en el puerto NEXT. Ver figura 5.75.
Figura 5.75: remove - Caso 3 - Paso 3 de 4 Como el nodo que contiene una referencia al caracter ’C’ queda sin referencias externas, autom´aticamente queda marcado para que la memoria que ocupa sea liberada por el recolector de basura de Java. Ver figura 5.76.
Figura 5.76: remove - Caso 3 - Recolector de basura
118
CAP´ITULO 5. LISTA 4. Se disminuye en una unidad la cantidad de nodos de la lista. Ver figura 5.77.
Figura 5.77: remove - Caso 3 - Paso 4 de 4 5. Finalmente, se establece en true el campo changed. Caso 4. La lista tiene m´as de dos nodos y el nodo actual se˜ nala un nodo que no es ni el primero ni el u ´ltimo nodo de la lista. Ver figura 5.78.
Figura 5.78: remove - Caso 4 - Precondici´on
1. Usaremos dos referencias temporales, una al nodo que se encuentra conectado a la derecha del nodo actual, llamada nextCurrent y otra al nodo conectado a la izquierda del nodo actual, llamada previousCurrent. Ver figura 5.79.
5.2. OPERACIONES DE UNA LISTA
119
Figura 5.79: remove - Caso 4 - Paso 1 de 5 2. Se actualiza current, el cual corresponde al siguiente del nodo actual. Ver figura 5.80.
Figura 5.80: remove - Caso 4 - Paso 2 de 5 3. Se conecta el nextCurrent del actual con previousCurrent en el puerto BACK. Ver figura 5.81.
Figura 5.81: remove - Caso 4 - Paso 3 de 5 4. Se conecta previousCurrent con nextCurrent en el puerto NEXT. Ver figura 5.82.
120
CAP´ITULO 5. LISTA
Figura 5.82: remove - Caso 4 - Paso 4 de 5 Debido a que el nodo que almacena la referencia al caracter ’B’ se ha quedado sin referencias externas, autom´aticamente queda marcado para que la memoria que ocupa sea liberada por el recolector de basura de Java. Ver figura 5.83.
Figura 5.83: remove - Caso 4 - Recolector de basura 5. Se disminuye en una unidad la cantidad de nodos de la lista. Ver figura 5.84.
5.2. OPERACIONES DE UNA LISTA
121
Figura 5.84: remove - Caso 4 - Paso 5 de 5 6. Finalmente, se establece true como valor en el campo changed. Al final la lista se podr´ıa ver como en la figura 5.85.
Figura 5.85: remove - Caso 4 - Poscondici´on
Es de anotar que las referencias temporales nextCurrent y previousCurrent no son absolutamente necesarias. Simplemente se utilizaron para facilitar la programaci´on de esta operaci´on. Al finalizar, estas referencias desaparecen de la memoria, es decir, se libera la memoria que ocupan.
5.2.3.
An´ alisis
Las operaciones de an´alisis permiten obtener informaci´on de la lista o de alguno de sus nodos. Este tipo de operaciones no afecta el valor del campo changed. get No recibe ning´ un par´ametro. Retorna la referencia al objeto, almacenada en el campo de datos del nodo actual. En caso de que el nodo actual sea indeterminado (null) se lanza una excepci´on.
CAP´ITULO 5. LISTA
122
En el caso de la lista de la figura 5.86, la operaci´on get retorna una referencia a una cadena cuyo valor es "ANA".
Figura 5.86: get
getIndex No recibe ning´ un par´ametro, retorna un entero con la posici´on del nodo actual en la lista. El primer nodo de la lista tiene la posici´on cero. Permitir que cada nodo conozca su posici´on en la lista puede generar un problema de actualizaci´on a la hora de eliminar nodos y adicionar nodos a la izquierda del nodo actual. Por otra parte, para poder determinar la posici´on, es necesario que current recorra la lista desde el primer nodo hasta el nodo actual. En el caso del ejemplo de la figura 5.87, la operaci´on getIndex retorna 1, lo cual indica que el nodo actual ocupa la posici´on 1 de la lista.
5.2. OPERACIONES DE UNA LISTA
123
Figura 5.87: getIndex
getSize No recibe ning´ un par´ametro, retorna un entero con el n´ umero de nodos de la lista, almacenado en el atributo length. En el caso del ejemplo de la figura 5.88, la operaci´on getSize retorna un 4, que indica que actualmente hay cuatro nodos en la lista.
Figura 5.88: getSize
isValidCurrent No recibe ning´ un par´ametro, retorna un valor de tipo boolean (false o true), dependiendo del valor de la referencia al nodo actual. En el caso de que sea null, el resultado es false. En el caso del ejemplo de la figura 5.89, isValidCurrent retorna true, lo que indica que el nodo actual es v´alido (diferente de null).
124
CAP´ITULO 5. LISTA
Figura 5.89: isValidCurrent - 1
Por el contrario, en el ejemplo de la figura 5.90, isValidCurrent retorna false, lo que indica que current es null.
Figura 5.90: isValidCurrent - 2
getChanged No recibe ning´ un par´ametro. Retorna el valor del atributo changed. toString Esta operaci´on construye una cadena (String) con el contenido de la lista. Para poder formar la cadena debe realizar un recorrido completo por los diferentes nodos que conforman la lista. En este caso, la cadena es formada por el contenido de cada nodo en un rengl´on, con un salto de l´ınea cada vez. Al finalizar, current termina se˜ nalando el mismo nodo que se˜ nalaba al iniciar la operaci´on. Ver figura 5.91.
5.2. OPERACIONES DE UNA LISTA
125
Figura 5.91: toString
5.2.4.
Localizaci´ on
Las operaciones de localizaci´on permiten posicionar el nodo actual en el siguiente, el anterior, el primero, el u ´ltimo o uno especificado por su ´ındice dentro de la lista. A pesar de que en estas operaciones se pueden ver modificaciones en el valor de la referencia null, se ha determinado que estas operaciones no van a modificar el valor del campo changed. goFirst Permite posicionar el nodo actual en el primer nodo de la lista. Por ejemplo, considere la lista de la figura 5.92.
Figura 5.92: goFirst - Precondici´on
126
CAP´ITULO 5. LISTA
Despu´es de aplicar el m´etodo, la lista es como la que se puede apreciar en la figura 10.36.
Figura 5.93: goFirst - Poscondici´on
goLast Permite posicionar el nodo actual en el u ´ltimo nodo de la lista. Por ejemplo, considere la lista de la figura 5.94.
Figura 5.94: goLast - Precondici´on Despu´es de aplicar el m´etodo, la lista es como la que se puede apreciar en la figura 5.95.
Figura 5.95: goLast - Poscondici´on
5.2. OPERACIONES DE UNA LISTA
127
goNext Permite posicionar el nodo actual en el siguiente nodo de la lista. En caso de que el nodo actual sea null, se lanza una excepci´on. Por ejemplo, considere la lista de la figura 5.96.
Figura 5.96: goNext - Precondici´on A continuaci´on de aplicar el m´etodo, la lista queda como la figura 5.97.
Figura 5.97: goNext - Poscondici´on
goBack Permite posicionar el nodo actual en el nodo anterior en la lista. En caso de que el nodo actual sea null, se lanza una excepci´on. Por ejemplo, considere la lista de la figura 5.98.
128
CAP´ITULO 5. LISTA
Figura 5.98: goBack - Precondici´on A continuaci´on de aplicar el m´etodo, la lista queda como la figura 5.99.
Figura 5.99: goBack - Poscondici´on
goTo Permite posicionar el nodo actual en el nodo especificado. Recibe por par´ametro el ´ındice del nodo que el usuario desea se˜ nalar con la referencia current. En caso de que el ´ındice no exista, se lanza una excepci´on. Por ejemplo, considere la lista de la figura 5.100.
Figura 5.100: goTo - Precondici´on
5.2. OPERACIONES DE UNA LISTA
129
Observe que el nodo actual ocupa la posici´on 1 en la lista (recuerde que se inicia en la posici´on 0). Suponga que desea ir al nodo de la posici´on 3. El resultado se puede apreciar en la figura 5.101.
Figura 5.101: goTo - Poscondici´on
5.2.5.
Persistencia
Las operaciones de persistencia permiten almacenar y recuperar la lista completa desde un archivo. La serializaci´on de objetos en Java permite realizar esta tarea de forma casi autom´atica. La serializaci´on es el proceso de escribir el estado de un objeto en un flujo de bytes (incluyendo los objetos que se est´en referenciando). Las operaciones de persistencia para la lista doblemente enlazada son: save: Almacena en un archivo el contenido de la lista. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Puede disparar una excepci´on si el archivo no puede ser creado o no se puede escribir en ´el. Al finalizar la operaci´on save, se pone en false el valor del atributo changed.
CAP´ITULO 5. LISTA
130
load: Carga a la memoria la lista completa. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Si no existe el archivo o no se puede leer, se dispara una excepci´on. Ver figura 5.102
Figura 5.102: Persistencia
6
Cola
Una cola es una estructura de datos similar a una lista sencillamente enlazada, pero con algunas restricciones. En una cola, los datos salen en el mismo orden en que han ingresado, es decir, el primero en entrar es el primero en ser atendido. Por otra parte, una cola no se puede recorrer, porque solo hay acceso a un elemento de la cola, el que se encuentre en la primera posici´on. Para que sea posible atender otro elemento, es necesario que el primer elemento de la cola sea eliminado de ella. Existen diferentes formas de implementar una cola. La implementaci´on propuesta en este documento es a trav´es de una lista sencillamente enlazada1 . Por lo tanto, las diferentes funcionalidades de la cola se hacen a trav´es de la lista interna. Una cola se compone de nodos en los cuales se pueden almacenar referencias a objetos. Los nodos est´an enlazados, sin embargo, el manejo que se le da a los enlaces es interno y el usuario no tiene acceso a ellos. 1
Ver Lista Sencillamente Enlazada.
CAP´ITULO 6. COLA
132
6.1.
Cola: Conceptos
En este documento se usa una cola que se compone de una lista sencillamente enlazada la cual permanecer´a oculta al usuario, y un atributo boolean que permite saber si la cola ha cambiado desde la u ´ltima vez que se guard´o en disco.
6.2.
Operaciones
Las operaciones a realizar sobre una cola se pueden clasificar de la siguiente manera: Construcci´ on: Establece una cola vac´ıa. Modificaci´ on: Operaciones que modifican la cola en su n´ umero de nodos o el contenido de alguno de ellos. Se tienen cuatro operaciones modificadoras: 1. newQueue: Establece una cola en su estado inicial, es decir, vac´ıa. 2. insert: Permite agregar un elemento a la cola. 3. getAndRemove: Elimina y retorna el elemento almacenado en la primera posici´on de la cola. An´ alisis: Son operaciones que permiten obtener informaci´on de la cola. Existen seis operaciones analizadoras: 1. get: Permite obtener la referencia al objeto, almacenada en el campo de datos del nodo de la primera posici´on de la cola. 2. search: Permite buscar un elemento en la cola. 3. isEmpty: Permite saber si la cola est´a vac´ıa o no. 4. getChanged: Permite obtener el valor del atributo changed. 5. toString: Construye una cadena con el contenido de la cola. Persistencia: Permite almacenar la cola en un archivo o recuperarla. Existen dos operaciones de persistencia: 1. save: Almacena la cola en disco. 2. load: Recupera la cola almacenada en disco para pasarla a memoria.
6.2. OPERACIONES
6.2.1.
133
Construcci´ on
El objetivo de esta operaci´on es establecer una cola vac´ıa. Ver figura 6.1.
Figura 6.1: Construcci´on
6.2.2.
Modificaci´ on
Las operaciones modificadoras permiten hacer cambios en la cola, ya sea porque se aumente o disminuya la cantidad de nodos. Las operaciones de modificaci´on son: newQueue Esta operaci´on elimina todos los nodos de la cola, dej´andola vac´ıa. La u ´nica diferencia con el estado inicial es que esta operaci´on deja en true el atributo changed. Una posible precondici´on se puede ver en la figura 6.2.
Figura 6.2: newQueue - Precondici´on
Al efectuar esta operaci´on, el resultado es como el de la figura 6.3.
CAP´ITULO 6. COLA
134
Figura 6.3: newQueue - Poscondici´on
insert Recibe la informaci´on que se va a almacenar en el campo de datos del nodo nuevo. El objetivo es agregar un nodo al final de la cola, es decir, a continuaci´on del u ´ltimo nodo. En caso de que la operaci´on no sea exitosa, se lanza una excepci´on. La operaci´on insert puede hacerse teniendo nodos en la cola o no. Una de las m´ ultiples precondiciones puede ser la de la figura 6.4, para la cual la poscondici´on es como se puede ver en la figura 6.5. Suponga que se desea insertar un objeto de tipo Character con valor X.
Figura 6.4: insert - Precondici´on
Figura 6.5: insert - Poscondici´on
Al final, el atributo changed toma el valor de true.
6.2. OPERACIONES
135
getAndRemove Retorna una referencia al objeto almacenado en el primer nodo de la cola. Antes de retornar, elimina el nodo, quedando en el primer nodo de la cola, el nodo que estaba a continuaci´on en la cola. Si la precondici´on es la de la figura 6.6, la poscondici´on correspondiente es la de la figura 6.7. Suponga que en la cola hay objetos de tipo Character y que el primer elemento de la cola es la letra A. La ejecuci´on de este m´etodo retorna una referencia al objeto Character con valor A y queda en el primer elemento de la cola otro objeto de tipo Character con valor B.
Figura 6.6: getAndRemove - Precondici´on
Figura 6.7: getAndRemove - Poscondici´on Al terminar, el atributo changed toma el valor de true.
6.2.3.
An´ alisis
Las operaciones de an´alisis permiten obtener informaci´on de la cola. get No recibe ning´ un par´ametro, retorna la referencia al objeto, almacenada en el campo de datos del primer nodo de la cola. En caso de que el nodo actual
136
CAP´ITULO 6. COLA
sea indeterminado (null) se lanza una excepci´on. A diferencia del m´etodo getAndRemove, get no elimina el nodo retornado. Suponga la cola de la figura 6.8. En este caso, se retorna una referencia al objeto tipo Character con valor A, y como no se elimina, contin´ ua siendo el elemento de la primera posici´on de la cola.
Figura 6.8: get - Precondici´on
search Recibe una referencia a un objeto con el fin de determinar si en la cola hay una referencia a un objeto equivalente. En caso de que exista, retorna el n´ umero de veces que se debe hacer uso del m´etodo getAndRemove para que este elemento se encuentre en el primer nodo de la cola. En caso de que no exista, retorna -1. El tipo de dato que retorna es int. Suponga que en la cola de datos de tipo Character se tienen los elementos A, B, C y D, y que se desea saber si hay una referencia a un objeto cuyo contenido sea C. El valor a retornar es 2, porque son dos veces que debe ejecutar el m´etodo getAndRemove para que ese objeto est´e referenciado por el primer nodo de la cola. Observe que la cola no sufre ninguna modificaci´on. Ver figura 6.9.
Figura 6.9: search - Precondici´on
6.2. OPERACIONES
137
isEmpty Retorna un valor de tipo boolean que indica si la cola est´a vac´ıa o no. Por ejemplo, de acuerdo a la precondic´on de la figura 6.10, este m´etodo debe retornar un valor boolean falso (false), porque la cola no est´a vac´ıa.
Figura 6.10: isEmpty - Precondici´on
getChanged No recibe ning´ un par´ametro, retorna el valor del atributo changed. toString Es un m´etodo que construye una cadena con la informaci´on almacenada en los diferentes nodos de la cola. En este caso, se forma la cadena sin eliminar ninguno de los nodos de la cola. La cadena es formada por el contenido de cada nodo separado por espacios en blanco. Ver figura 6.11.
Figura 6.11: toString Tomando la situaci´on de la figura 6.11, la operaci´on toString retorna la cadena: A
B
C
D
CAP´ITULO 6. COLA
138
6.2.4.
Persistencia
Las operaciones de persistencia son las que permiten almacenar y recuperar la cola completa. La serializaci´on de objetos en Java permite realizar esta tarea. La serializaci´on es el proceso de escribir el estado de un objeto en un flujo de bytes. Esto es u ´til cuando se quiere salvar el estado de un programa en un ´area de almacenamiento persistente, como es un archivo. M´as adelante se pueden recuperar estos objetos usando el proceso de deserializaci´on. Las operaciones de persistencia soportadas por la liber´ıa de clase Queue son: save: Almacena en un archivo el contenido de la cola y pone en false el valor del atributo changed. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Puede disparar una excepci´on si el archivo no puede ser creado o no se puede escribir en ´el. load: Carga a la memoria la cola completa. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Si no existe el archivo o no se puede leer, se dispara una excepci´on. Ver figura 6.12
Figura 6.12: Persistencia
7 Pila
Una pila es una estructura de datos similar a una lista sencillamente enlazada, pero con algunas restricciones. En una pila, los datos salen en orden inverso a la entrada, es decir, el u ´ltimo en entrar es el primero en ser atendido. Por otra parte, una pila no se puede recorrer, porque solo hay acceso a un elemento de la pila, el que se encuentre en la primera posici´on. Para que sea posible atender otro elemento, es necesario que el primer elemento de la pila sea eliminado de ella. Existen diferentes formas de implementar una pila. La implementaci´on propuesta en este documento es a trav´es de una lista sencillamente enlazada1 . Por lo tanto, las diferentes funcionalidades de la pila se hacen a trav´es de la lista interna. Una pila se compone de nodos en los cuales se pueden almacenar referencias a objetos. Los nodos est´an enlazados, sin embargo, el manejo que se le da a los enlaces es interno y el usuario no tiene acceso a ellos. 1
Ver Lista Sencillamente Enlazada.
CAP´ITULO 7. PILA
140
7.1.
Pila: Conceptos
En este documento se usa una pila que se compone de una lista sencillamente enlazada la cual permanecer´a oculta al usuario, y un atributo boolean que permite saber si la pila ha cambiado desde la u ´ltima vez que se guard´o en disco.
7.2.
Operaciones
Las operaciones a realizar sobre una pila se pueden clasificar de la siguiente manera: Construcci´ on: Establece una pila vac´ıa. Modificaci´ on: Operaciones que modifican la pila en su n´ umero de nodos o el contenido de alguno de ellos. Se tienen cuatro operaciones modificadoras: 1. newStack: Establece una pila en su estado inicial, es decir, vac´ıa. 2. push: Permite agregar un elemento a la pila. 3. pop: Elimina y retorna el elemento almacenado en la primera posici´on de la pila. An´ alisis: Son operaciones que permiten obtener informaci´on de la pila. Existen seis operaciones analizadoras: 1. peek: Permite obtener la referencia al objeto, almacenada en el campo de datos del nodo de la primera posici´on de la pila. 2. search: Permite buscar un elemento en la pila. 3. isEmpty: Permite saber si la pila est´a vac´ıa o no. 4. getChanged: Permite obtener el valor del atributo changed. 5. toString: Construye una cadena con el contenido de la pila. Persistencia: Permite almacenar la pila en un archivo o recuperarla. Existen dos operaciones de persistencia: 1. save: Almacena la pila en disco. 2. load: Recupera la pila almacenada en disco para pasarla a memoria.
7.2. OPERACIONES
7.2.1.
141
Construcci´ on
El objetivo de esta operaci´on es establecer una pila vac´ıa. Ver figura 7.1.
Figura 7.1: Construcci´on
7.2.2.
Modificaci´ on
Las operaciones modificadoras permiten hacer cambios en la pila, ya sea porque se aumente o disminuya la cantidad de nodos. Las operaciones de modificaci´on son: newStack Esta operaci´on elimina todos los nodos de la pila, dej´andola vac´ıa. La u ´nica diferencia con el estado inicial es que esta operaci´on deja en true el atributo changed. Una posible precondici´on se puede ver en la figura 7.2.
Figura 7.2: newStack - Precondici´on
Al efectuar esta operaci´on, el resultado es como el de la figura 7.3.
CAP´ITULO 7. PILA
142
Figura 7.3: newStack - Poscondici´on
push Recibe la informaci´on que se va a almacenar en el campo de datos del nodo nuevo. El objetivo es agregar un nodo al inicio de pila, es decir, antes del primer nodo. En caso de que la operaci´on no sea exitosa, se lanza una excepci´on. La operaci´on push puede hacerse teniendo nodos en la pila o no. Una de las m´ ultiples precondiciones puede ser la de la figura 7.4, para la cual la poscondici´on es como se puede ver en la figura 7.5. Suponga que se desea insertar un objeto de tipo Character con valor X.
Figura 7.4: push - Precondici´on
Figura 7.5: push - Poscondici´on
Al final, el atributo changed toma el valor de true.
7.2. OPERACIONES
143
pop Retorna una referencia al objeto almacenado en el primer nodo de la pila. Antes de retornar, elimina el nodo, quedando en el primer nodo de la pila, el nodo que estaba a continuaci´on en la pila. Si la precondici´on es la de la figura 7.6, la poscondici´on correspondiente es la de la figura 7.7. Suponga que en la pila hay objetos de tipo Character y que el primer elemento de la pila es la letra A. La ejecuci´on de este m´etodo retorna una referencia al objeto Character con valor A y queda en el primer elemento de la pila otro objeto de tipo Character con valor B.
Figura 7.6: pop - Precondici´on
Figura 7.7: pop - Poscondici´on Al terminar, el atributo changed toma el valor de true.
7.2.3.
An´ alisis
Las operaciones de an´alisis permiten obtener informaci´on de la pila. peek No recibe ning´ un par´ametro, retorna la referencia al objeto, almacenada en el campo de datos del primer nodo de la pila. En caso de que el nodo actual
144
CAP´ITULO 7. PILA
sea indeterminado (null) se lanza una excepci´on. A diferencia del m´etodo pop, peek no elimina el nodo retornado. Suponga la pila de la figura 7.8. En este caso, se retorna una referencia al objeto tipo Character con valor A, y como no se elimina, contin´ ua siendo el elemento de la primera posici´on de la pila.
Figura 7.8: peek - Precondici´on
search Recibe una referencia a un objeto con el fin de determinar si en la pila hay una referencia a un objeto equivalente. En caso de que exista, retorna el n´ umero de veces que se debe hacer uso del m´etodo pop para que este elemento se encuentre en el primer nodo de la pila. En caso de que no exista, retorna -1. El tipo de dato que retorna es int. Suponga que en la pila de datos de tipo Character se tienen los elementos A, B, C y D, y que se desea saber si hay una referencia a un objeto cuyo contenido sea C. El valor a retornar es 2, porque son dos veces que debe ejecutar el m´etodo pop para que ese objeto est´e referenciado por el primer nodo de la pila. Observe que la pila no sufre ninguna modificaci´on. Ver figura 7.9.
Figura 7.9: search - Precondici´on
7.2. OPERACIONES
145
isEmpty Retorna un valor de tipo boolean que indica si la pila est´a vac´ıa o no. Por ejemplo, de acuerdo a la precondic´on de la figura 7.10, este m´etodo debe retornar un valor boolean falso (false), porque la pila no est´a vac´ıa.
Figura 7.10: isEmpty - Precondici´on
getChanged No recibe ning´ un par´ametro, retorna el valor del atributo changed. toString Es un m´etodo que construye una cadena con la informaci´on almacenada en los diferentes nodos de la pila. En este caso, se forma la cadena sin eliminar ninguno de los nodos de la pila. La cadena es formada por el contenido de cada nodo separado por espacios en blanco. Ver figura 7.11.
Figura 7.11: toString Tomando la situaci´on de la figura 7.11, la operaci´on toString retorna la cadena: A
B
C
D
CAP´ITULO 7. PILA
146
7.2.4.
Persistencia
Las operaciones de persistencia son las que permiten almacenar y recuperar la pila completa. La serializaci´on de objetos en Java permite realizar esta tarea. La serializaci´on es el proceso de escribir el estado de un objeto en un flujo de bytes. Esto es u ´til cuando se quiere salvar el estado de un programa en un ´area de almacenamiento persistente, como es un archivo. M´as adelante se pueden recuperar estos objetos usando el proceso de deserializaci´on. Las operaciones de persistencia soportadas por la liber´ıa de clase Queue son: save: Almacena en un archivo el contenido de la pila y pone en false el valor del atributo changed. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Puede disparar una excepci´on si el archivo no puede ser creado o no se puede escribir en ´el. load: Carga a la memoria la pila completa. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Si no existe el archivo o no se puede leer, se dispara una excepci´on. Ver figura 10.38
Figura 7.12: Persistencia
8
´ Arbol Un ´arbol es una de las estructuras de datos m´as utilizadas en las ciencias de la computaci´on. Est´a formado por nodos y enlaces de una manera jer´arquica, donde se depende de un nodo principal llamado nodo ra´ız, del cual se desprenden otros nodos llamados hijos del nodo ra´ız. A su vez, de cada uno de los hijos del nodo ra´ız se pueden derivar hijos e hijos de los hijos, y as´ı sucesivamente. Existen ´arboles con recorrido descendente u ´nicamente y ´arboles con enlace al padre que pueden ser recorridos de arriba hacia abajo y viceversa. Este documento trata de los ´arboles n-arios con enlace al padre. Es importante anotar que cada nodo del ´arbol puede ser el nodo ra´ız de un sub´arbol que hace parte del ´arbol.
8.1.
Clases de ´ arboles
En las ciencias de la computaci´on existe una variedad de ´arboles de diferentes clases. Entre las m´as representativas se tienen: N-arios
´ CAP´ITULO 8. ARBOL
148 Binarios De expresi´on AVL B B+ Orientados Rojinegros De ensanchamiento De codificaci´on de Huffman
8.2.
Aplicaciones de los ´ arboles
Los ´arboles pueden utilizarse en diferentes tipos de aplicaciones. Se destacan entre ellas las siguientes: Sistemas de archivos para sistemas operativos Manejo de ´ındices para la localizaci´on de registros en bases de datos Los nombres de dominio en Internet (DNS) El espacio de nombres de identificadores de objetos en el Protocolo SNMP (administraci´on de redes) Ordenamiento B´ usqueda Manejo de expresiones aritm´eticas en compiladores Compresi´on de datos
8.3. CONCEPTOS GENERALES
8.3.
149
Conceptos generales
Para utilizar adecuadamente la estructura de datos ´arbol, es importante conocer las siguientes definiciones: nodo: Es cada elemento del ´arbol. ra´ız: Es el nodo principal del ´arbol. Es el u ´nico nodo que no tiene padre. padre: A cada nodo del ´arbol, excepto al nodo ra´ız, le llega un enlace de un nivel superior. El nodo del cual proviene ese enlace se conoce como padre. hijo: Es cada una de las ramificaciones directas de un nodo. hermano: Dos o m´as nodos son hermanos si son hijos del mismo padre. hoja: Es un nodo que no tiene hijos. nodo no terminal: Es un nodo que posee al menos un hijo. Tambi´en se conoce como nodo interno. camino: Un camino es el conjunto de nodos que se deben visitar con el fin de llegar de un nodo a otro. Para ir de un nodo a otro (en un mismo ´arbol), s´olo existe un u ´nico camino. longitud: Es el n´ umero de enlaces que tiene un camino. Tambi´en se conoce como longitud del camino. descendiente: Un nodo a es descendiente de un nodo b si se puede llegar desde b hasta a a trav´es de un camino. ancestro: Un nodo a es ancestro de un nodo b si el nodo a puede ser el punto de partida de un camino que llegue al nodo b. tama˜ no: El tama˜ no de un nodo es el n´ umero de descendientes de un nodo incluy´endose el nodo. El tama˜ no del ´arbol es equivalente al tama˜ no en el nodo ra´ız. altura: La altura de un nodo es la longitud del camino que va desde el nodo hasta la hoja m´as profunda entre las hojas descendientes del nodo. La altura del ´arbol es equivalente a la la altura en el nodo ra´ız.
´ CAP´ITULO 8. ARBOL
150
nivel: Cada nodo tiene un nivel dentro de un ´arbol. En el nivel 0 est´a el nodo ra´ız. En el nivel 1 est´an los hijos del nodo ra´ız. En el nivel 2 se encuentran los hijos de los hijos del nodo ra´ız, y as´ı sucesivamente. profundidad: La profundidad de un nodo es la longitud del camino que va desde la ra´ız hasta ese nodo. La profundidad y el nivel son equivalentes. grado: El grado de un nodo es el n´ umero de hijos que tiene el nodo. peso: El peso de un nodo es el n´ umero de descendientes del nodo.
8.4.
Formas de recorrer un ´ arbol
Las formas m´as comunes para hacer un recorrido de un ´arbol n-ario son: pre-orden: Se examina el nodo ra´ız y a continuaci´on se examina cada uno de los hijos del nodo ra´ız, de izquierda a derecha, en recorrido pre-orden. post-orden: Se examina cada uno de los hijos del nodo ra´ız de izquierda a derecha, en recorrido post-orden y a continuaci´on se examina el nodo ra´ız. por niveles: Se examina primero el nivel 0 (nodo ra´ız), a continuaci´on el nivel 1 (los hijos del nodo ra´ız de izquierda a derecha), luego el nivel 2, a continuaci´on el nivel 3 y as´ı sucesivamente por todos los niveles del ´arbol. in-orden: Es un recorrido solo aplicable a los ´arboles binarios. Se examina primero el hijo izquierdo en recorrio in-orden, luego el nodo ra´ız y posteriormente el hijo derecho en recorrido in-orden.
8.5.
Componentes de un ´ arbol
El ´arbol del cual trata este documento, se compone de un nodo principal o nodo ra´ız. Este nodo puede ser enlazado con sus hijos que tambi´en son nodos. Un nodo para un ´arbol se puede ver en la figura 8.1.
´ 8.5. COMPONENTES DE UN ARBOL
151
Figura 8.1: Nodo (1)
Observe que el contenido del campo de datos del nodo es una referencia a un objeto y no un objeto almacenado all´ı directamente. Sin embargo, con el fin de facilitar la interpretaci´on de los nodos en las im´agenes de este documento, vamos a utilizar los nodos como en la figura 8.2, donde se ha cambiado la disposici´on de los puertos y que en lugar de dibujar la referencia al objeto, se ha dibujado el contenido del objeto referenciado en el espacio del campo de datos del nodo. Por otra parte, en las im´agenes de este documento no ser´an tenidos en cuenta los campos name, maxPort, numberInputLinks ni flag.
Figura 8.2: Nodo (2) Los ´arboles descritos en este documento tienen nodos con enlace al padre. Este enlace ocupa el puerto n´ umero cero (0). Utilizaremos la constante PARENT con valor 0 para referirnos al puerto donde un nodo se enlaza con su nodo padre. Ver figura 8.3.
Figura 8.3: Nodo (3) Para realizar toda la gesti´on de un ´arbol propuesta en este documento, se necesitan los siguientes atributos:
152
´ CAP´ITULO 8. ARBOL Una referencia a nodo llamada root, para se˜ nalar al nodo ra´ız. Una referencia a nodo llamada current, para se˜ nalar uno nodo cualquiera en el ´arbol, en un momento dado. Un atributo entero llamado size para controlar la cantidad de nodos del ´arbol. Un atributo entero llamado maxPort para controlar el n´ umero m´aximo de puertos de cada nodo. En caso de no utilizarse este atributo, se asume un valor de cero, el cual indica que el ´arbol no tendr´a ninguna restricci´on en cuanto al n´ umero de puertos de cada nodo del ´arbol. Un atributo entero llamado height para almacenar la altura del ´arbol. Un atributo boolean llamado changed que permite saber si se han realizado cambios en el ´arbol desde la u ´ltima vez que la estructura se guard´o en disco.
El atributo changed tampoco se ha considerado en las im´agenes. Solo se tiene en cuenta en este documento cuando se necesite expl´ıcitamente. Las referencias a nodo (tipo Node) han sido definidas en Nodos y enlaces y est´a codificada en Node.java. Una imagen de un ´arbol puede verse en la figura 8.4.
´ 8.5. COMPONENTES DE UN ARBOL
153
´ n-ario (1) Figura 8.4: Arbol
Es de anotar que para simplificar los dibujos y facilitar su interpretaci´on, en adelante los ´arboles se ver´an como en las figuras 8.5 y 8.6. Si no se especifica el n´ umero del puerto, se da por hecho que los hijos inician en el hijo 1 y el siguiente es el hijo 2 y as´ı sucesivamente. Adem´as, se da por hecho que un enlace entre un padre y un hijo es bidireccional, a menos que se especifique lo contrario.
´ Figura 8.5: Arbol n-ario (2)
´ CAP´ITULO 8. ARBOL
154
Cuando aparece en el diagrama un n´ umero al lado de cada uno de los enlaces, este n´ umero indica el n´ umero del puerto. Esto ocurre cuando los n´ umeros de los puertos asociados a los hijos de un nodo no cumplen con la secuencia natural, o porque se ha eliminado alguno de los hijos en un puerto intermedio. Ver figura 8.6.
´ Figura 8.6: Arbol n-ario (3)
Nota importante: En este documento se especifica un ´arbol N-Ario con enlace al padre. Un ´arbol n-ario puede tener nodos con cualquier n´ umero de hijos. El n´ umero de hijo puede limitarse con el atributo maxPort. Si este atributo tiene un valor de cero, significa que los nodos que pertenecen al ´arbol no tendr´an ninguna restricci´on en la cantidad de hijos que pueda tener. Existe una ´arbol, muy utilizado en las ciencias de la computaci´on, limitado a m´aximo dos hijos por cada nodo. La estructura de datos mencionada se llama ´ Arbol Binario. Para implementar un ´arbol binario, es necesario establecer en 3, al atributo maxPort, debido al puerto reservado para conectar cada nodo con su padre. Todas las operaciones que se le pueden aplicar a un ´arbol n-ario se le pueden aplicar a un ´arbol binario. En un ´arbol binario, los hijos se llaman hijo izquierdo e hijo derecho y ocupan los ´ındices 1 y 2 respectivamente.
8.6.
Operaciones sobre un ´ arbol n-ario
Las clases de operaciones que se pueden realizar sobre un ´arbol n-ario se pueden clasificar de la siguiente manera: Construcci´on: Son las operaciones que permiten establecer un ´arbol nario vac´ıo, con el campo maxPort en cero o con el valor que reciba por par´ametro.
´ 8.6. OPERACIONES SOBRE UN ARBOL N-ARIO
155
Modificaci´ on: Las operaciones de modificaci´on permiten hacer los cambios en el ´arbol, ya sea porque se aumente o disminuya la cantidad de nodos o porque sea actualizado el contenido de alg´ un nodo. Las operaciones modificadoras son: 1. newTree: Establece un ´arbol en su estado inicial, es decir, vac´ıo. 2. addRoot: Permite adicionar el nodo ra´ız al ´arbol. En caso de que el nodo ra´ız del ´arbol exista, se actualiza su contenido. Si la operaci´on no es existosa, se lanza una excepci´on. 3. addSon: Permite adicionar un hijo al ´arbol, con el ´ındice especificado en el par´ametro. Si el hijo existe, se actualiza su contenido. Si la operaci´on no es existosa, se lanza una excepci´on. 4. update: Permite actualizar el contenido del campo de datos del nodo actual. En caso de que el nodo actual sea null se genera una excepci´on. 5. removeSubTree: Permite eliminar el sub´arbol que inicia en el nodo actual. En caso de que el nodo actual sea null se genera una excepci´on. 6. removeLeaf: Permite eliminar el nodo actual siempre y cuando sea hoja. En caso de que el nodo actual no sea hoja o sea null se genera una excepci´on. An´ alisis: Las operaciones de an´alisis permiten obtener informaci´on del ´arbol o de alg´ un nodo. Estas operaciones son: 1. get: Permite obtener la referencia al objeto, almacenada en el campo de datos del nodo actual. 2. getSize: Permite obtener el n´ umero de nodos del ´arbol. 3. getIndex: Permite conocer el ´ındice del nodo actual como hijo de su padre. 4. getHeight: Permite obtener la altura del ´arbol en el nodo actual. 5. getWeight: Permite obtener el peso del ´arbol en el nodo actual. 6. getLeastNumberPort: Retorna el puerto libre con ´ındice menor del nodo actual.
´ CAP´ITULO 8. ARBOL
156
7. isValidCurrent: Permite saber si el nodo actual es v´alido o no. El nodo actal es v´alido si su valor es distinto de null. Retorna un valor false o true. 8. isEmpty: Permite saber si el ´arbol est´a vac´ıo o no. Retorna un valor false o true. 9. currentIsLeaf: Permite saber si el nodo actual es hoja o no. Retorna un valor false o true. 10. currentIsRoot: Permite saber si el nodo actual es el nodo ra´ız o no. Retorna un valor false o true. 11. currentHasSon: Permite saber si el nodo actual tiene un hijo con el ´ındice especificado. Retorna un valor false o true. 12. preOrder: Permite obtener una lista sencillamente enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol, en el recorrido pre-orden. 13. postOrder: Permite obtener una lista sencillamente enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol, en el recorrido post-orden. 14. levels: Permite obtener una lista sencillamente enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol, en el recorrido por niveles. 15. inOrder: Permite obtener una lista sencillamente enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol, en el recorrido in-orden. 16. toString: Construye una cadena con el contenido del ´arbol, haciendo un recorrido por niveles1 a todo el ´arbol. Localizaci´ on: Las operaciones de localizaci´on permiten posicionar el nodo actual en el nodo ra´ız, en el padre del nodo actual o en alguno de los hijos del nodo actual. Las operaciones de localizaci´on son: 1. goRoot: Modifica la referencia del nodo actual para que se˜ nale ahora al nodo ra´ız del ´arbol. 2. goParent: Modifica la referencia del nodo actual para que se˜ nale ahora al padre del nodo actual, es decir, sube un nivel en el ´arbol, siempre y cuando el nodo actual no sea el nodo ra´ız. 1
Decisi´on arbitraria por parte del autor.
8.7. DETALLES DE LAS OPERACIONES
157
3. goSon: Modifica la referencia del nodo actual para que se˜ nale ahora a uno de los hijos del nodo actual, es decir, baja un nivel en el ´arbol. Persistencia: Las operaciones de persistencia permiten almacenar el ´arbol en un medio persistente (archivo). De igual manera, se permite recuperar un ´arbol desde un archivo de datos. Las operaciones de persistencia son: 1. save: Permite almacenar el ´arbol en un archivo. 2. load: Permite recuperar un ´arbol que se encuentra almacenado en un archivo.
8.7.
Detalles de las operaciones
8.7.1.
Construcci´ on
El objetivo de esta operaci´on es asignar null a las referencias root y current. Tambi´en inicializa en 0 (cero) el atributo size. El n´ umero m´aximo de puertos es inicializado con el valor recibido por par´ametro. En caso de que no se reciba ning´ un par´ametro se asume 0 (cero), lo que indica que el ´arbol no tendr´a ninguna restricci´on en cuanto al n´ umero de hijos se refiere. Se inicializa el atributo height en -1, porque la altura de un ´arbol vac´ıo es -1 y finalmente, se establece en false el atributo changed. Ver figura 8.7.
Figura 8.7: Construcci´on
´ CAP´ITULO 8. ARBOL
158
8.7.2.
Modificaci´ on
Las operaciones de modificaci´on permiten hacer los cambios en el ´arbol, ya sea porque se aumente o disminuya la cantidad de nodos o porque sea actualizado el contenido de alg´ un nodo.
newTree Esta operaci´on elimina todos los nodos del ´arbol, dej´andolo vac´ıo. La u ´nica diferencia con el estado inicial es que esta operaci´on deja en true el atributo changed. Una posible precondici´on se puede ver en la figura 8.8.
Figura 8.8: newTree - Precondici´on
Al efectuar esta operaci´on, el resultado es como el de la figura 8.9.
Figura 8.9: newTree - Poscondici´on
8.7. DETALLES DE LAS OPERACIONES
159
addRoot Recibe la informaci´on que se va a almacenar en el campo de datos del nuevo nodo. El objetivo es crear el nodo ra´ız del ´arbol. En caso de que el nodo ra´ız del ´arbol exista, se actualiza su contenido. Si la operaci´on no es existosa, se lanza una excepci´on. Se consideran dos casos: El ´arbol est´a vac´ıo y el ´arbol no est´a vac´ıo. Caso 1: El ´arbol est´a vac´ıo. Ver precondici´on en la figura 8.10.
Figura 8.10: addRoot - Precondici´on - Caso 1 Suponga que se desea adicionar una referencia a un objeto de tipo Character con la letra X a un ´arbol vac´ıo. A continuaci´on se pueden ver los pasos que permiten adicionar el nodo ra´ız del ´arbol. 1. Obtener memoria para el nuevo nodo. Si no hubo ning´ un problema con la solicitud de memoria, se puede contar con un nuevo nodo, listo para ser utilizado en el ´arbol. Este nodo tiene un solo puerto y su valor es null. Para simplificar los dibujos, no se ha especificado el puerto de cada nodo nuevo. Este puerto es el puerto con ´ındice cero (0) y ser´a utilizado para enlazar a cada nodo con su respectivo padre. Ver figura 8.11.
Figura 8.11: addRoot - Caso 1 - Paso 1
2. Establecer el campo de datos del nuevo nodo, con la informaci´on obtenida por par´ametro. Ver figura 8.12.
160
´ CAP´ITULO 8. ARBOL
Figura 8.12: addRoot - Caso 1 - Paso 2
3. Posicionar el nodo actual. En este caso, current debe referenciar al nuevo nodo. Ver figura 8.13.
Figura 8.13: addRoot - Caso 1 - Paso 3
4. La referencia root debe se˜ nalar al nuevo nodo. Ver figura 8.14.
Figura 8.14: addRoot - Caso 1 - Paso 4
5. Luego, aumenta la cantidad de nodos del ´arbol. Ver figura 8.15.
Figura 8.15: addRoot - Caso 1 - Paso 5 Al terminar, el atributo changed toma el valor de true.
8.7. DETALLES DE LAS OPERACIONES
161
Caso 2: Existen nodos en el ´arbol. Ver precondici´on en la figura 8.16.
Figura 8.16: addRoot - Precondici´on - Caso 2 Suponga que se desea adicionar una referencia a un objeto de tipo Character con la letra X a un ´arbol no vac´ıo. A continuaci´on se pueden ver los pasos que permiten actualizar el nodo ra´ız del ´arbol. 1. Se ubica el nodo actual se˜ nalando al nodo ra´ız del ´arbol. Ver figura 8.17.
Figura 8.17: addRoot - Caso 2 - Paso 1
2. Se actualiza el campo de datos del nodo actual. Ver figura 8.18. Luego, se establece en true el atributo changed.
162
´ CAP´ITULO 8. ARBOL
Figura 8.18: addRoot - Caso 2 - Paso 2
addSon Recibe la informaci´on que se va a almacenar en el campo de datos del nuevo nodo y un n´ umero entero con el que se indica el n´ umero del hijo que se desea adicionar. El objetivo es crearle un hijo al nodo actual con el ´ındice especificado. En caso de que el hijo que se quiere crear exista, se actualiza su contenido. Si el ´arbol est´a vac´ıo, se crea el nodo ra´ız. Si la operaci´on no es existosa, por ejemplo, si el ´ındice no se puede utilizar por la restricci´on del atributo maxPort, se lanza una excepci´on. Se consideran tres casos: El hijo existe, el hijo no existe y el ´arbol est´a vac´ıo. Caso 1: El ´arbol tiene nodos y el hijo que se desea a˜ nadir existe. Suponga que se desea adicionar una referencia a un objeto de tipo Character con la letra X al hijo del nodo actual con ´ındice 2. Ver precondici´on en la figura 8.19.
8.7. DETALLES DE LAS OPERACIONES
163
Figura 8.19: addSon - Precondici´on - Caso 1 A continuaci´on se pueden ver los pasos que permiten actualizar el contenido del campo de datos del hijo especificado. 1. Se sobreescribe el campo de datos del nodo conectado en el puerto especificado, con la referencia al objeto recibida por par´ametro. Ver figura 8.20.
Figura 8.20: addSon - Caso 1 - Paso 1
164
´ CAP´ITULO 8. ARBOL
2. Se ubica el nodo actual en el nodo que acaba de modificar. Ver figura 8.21.
Figura 8.21: addSon - Caso 1 - Paso 2 Luego, se establece en true el atributo changed. Caso 2: El ´arbol tiene nodos y el hijo que se desea a˜ nadir no existe. Suponga que se desea adicionar una referencia a un objeto de tipo Character con la letra X al hijo del nodo actual con ´ındice 2. Ver precondici´on en la figura 8.22.
Figura 8.22: addSon - Precondici´on - Caso 2 A continuaci´on se pueden ver los pasos que permiten crear un nuevo hijo al nodo actual con el ´ındice especificado.
8.7. DETALLES DE LAS OPERACIONES
165
1. Obtener memoria para el nuevo nodo. Si no hubo ning´ un problema con la solicitud de memoria, se puede contar con un nuevo nodo, listo para ser utilizado en el ´arbol. Este nodo tiene un solo puerto y su valor es null. Ver figura 8.23.
Figura 8.23: addSon - Caso 2 - Paso 1
2. Establecer el campo de datos del nuevo nodo con la informaci´on obtenida por par´ametro. Ver figura 8.24.
166
´ CAP´ITULO 8. ARBOL
Figura 8.24: addSon - Caso 2 - Paso 2
3. Se enlaza el nodo actual con el nuevo nodo en el puerto especificado. Recuerde que el puerto 0 del nodo actual est´a reservado para el enlace con el padre, por lo tanto, el hijo 2 ocupa el puerto 2. Ver figura 8.25.
Figura 8.25: addSon - Caso 2 - Paso 3
4. Se enlaza el nuevo nodo con el actual en el puerto PARENT. Ver figura 8.26.
8.7. DETALLES DE LAS OPERACIONES
167
Figura 8.26: addSon - Caso 2 - Paso 4 (1)
Debido a que cada enlace es bidireccional, la imagen anterior es equivalente a la de la figura 8.27.
Figura 8.27: addSon - Caso 2 - Paso 4 (2)
5. Se ubica el nodo actual se˜ nalando el nuevo nodo. 8.28.
´ CAP´ITULO 8. ARBOL
168
Figura 8.28: addSon - Caso 2 - Paso 5
6. Se aumenta la cantidad de nodos del ´arbol. Ver figura 8.29.
Figura 8.29: addSon - Caso 2 - Paso 6 Finalmente, se establece en true el atributo changed. Caso 3: El ´arbol est´a vac´ıo. En este caso, hace lo mismo que addRoot cuando el ´arbol es vac´ıo. Ver p´agina 159. update Recibe la informaci´on que se va a almacenar en el campo de datos del nodo actual. En caso de que el nodo actual sea null (arbol vac´ıo), se lanza una
8.7. DETALLES DE LAS OPERACIONES
169
excepci´on. Ver precondici´on en la figura 8.30.
Figura 8.30: update - Precondici´on Suponga que se desea actualizar la referencia a objeto contenida en el nodo actual con una referencia a un objeto de tipo Character con la letra X. A continuaci´on se puede ver el u ´nico paso que permite actualizar el contenido del campo de datos del nodo actual. 1. Se sobreescribe el campo de datos del nodo actual, con la referencia al objeto, recibida por par´ametro. Ver figura 8.31.
Figura 8.31: update - Poscondici´on Al terminar, establee en true el atributo changed.
´ CAP´ITULO 8. ARBOL
170 removeSubTree
Permite eliminar el sub´arbol que inicia en el nodo actual. El nodo actual pasa a ser el padre del nodo a partir del cual se elimina el sub´arbol. Si el nodo actual es null se lanza una excepci´on. Se consideran dos casos: El actual tambi´en es el nodo ra´ız y el actual es otro nodo, diferente al nodo ra´ız. Caso 1: El nodo actual es tambi´en el nodo ra´ız. En este caso, se desea eliminar todo el ´arbol. Ver una posible precondici´on en la figura 8.32.
Figura 8.32: removeSubTree - Precondici´on - Caso 1 A continuaci´on se pueden ver los pasos necesarios para eliminar el sub´arbol a partir del nodo ra´ız. 1. La referencia root se actualiza a null. Ver figura 8.33.
8.7. DETALLES DE LAS OPERACIONES
171
Figura 8.33: removeSubTree - Caso 1 - Paso 1
2. La referencia current se actualiza a null. Ver figura 8.34.
Figura 8.34: removeSubTree - Caso 1 - Paso 2 Todo el ´arbol queda marcado autom´aticamente para ser eliminado por el recolector de basura de Java, al no tener ninguna referencia externa2 . Ver figura 8.35.
2
Existen lenguajes de programaci´on como C++ que no tienen recolector de basura. En estos lenguajes es necesario programar el llamado a las instrucciones de liberaci´on de la memoria ocupada por los nodos que se van a eliminar.
172
´ CAP´ITULO 8. ARBOL
Figura 8.35: removeSubTree - Caso 1 - Recolector de basura (1) Despu´es de que el recolector de basura ha eliminado los nodos que no ten´ıan referencia externa, se puede ver como en la figura 8.36.
Figura 8.36: removeSubTree - Caso 1 - Recolector de basura (2)
3. Se actualiza el atributo size con valor de cero (0). Ver figura 8.37.
Figura 8.37: removeSubTree - Caso 1 - Paso 3 Para terminar, establece en true el valor del atributo changed. Caso 2: El nodo actual se˜ nala un nodo diferente al nodo ra´ız. Ver una posible precondici´on en la figura 8.38.
8.7. DETALLES DE LAS OPERACIONES
173
Figura 8.38: removeSubTree - Precondici´on - Caso 2 A continuaci´on se pueden ver los pasos necesarios para eliminar el sub´arbol a partir del nodo actual. 1. Se obtiene el ´ındice del nodo actual como hijo de su padre. En el ejemplo se obtiene un 2. Ver figura 8.39.
174
´ CAP´ITULO 8. ARBOL
Figura 8.39: removeSubTree - Caso 2 - Paso 1
2. Se ubica el nodo actual como el padre del nodo actual, es decir, se sube un nivel. Ver figura 8.40.
8.7. DETALLES DE LAS OPERACIONES
175
Figura 8.40: removeSubTree - Caso 2 - Paso 2 (1) Debido a que en los dibujos, los enlaces son bidireccionales, la imagen anterior es equivalente a la de la figura 8.41.
176
´ CAP´ITULO 8. ARBOL
Figura 8.41: removeSubTree - Caso 2 - Paso 2 (2)
3. Se desconecta el puerto 2 (correspondiente al ´ındice obtenido en el paso 1). Ver figura 8.42.
8.7. DETALLES DE LAS OPERACIONES
177
Figura 8.42: removeSubTree - Caso 2 - Paso 3 Todo el sub´arbol queda marcado autom´aticamente para ser eliminado por el recolector de basura de Java, al no tener ninguna referencia externa. Ver figura 8.43.
178
´ CAP´ITULO 8. ARBOL
Figura 8.43: removeSubTree - Caso 2 - Recolector de basura (1) Despu´es de que el recolector de basura ha eliminado los nodos que no ten´ıan referencia externa, se puede ver como en la figura 8.44.
8.7. DETALLES DE LAS OPERACIONES
179
Figura 8.44: removeSubTree - Caso 2 - Recolector de basura (2)
4. Se crea una referencia temporal para se˜ nalar el nodo actual, llamada temporal. Ver figura 8.45.
Figura 8.45: removeSubTree - Caso 2 - paso 4
5. Se ubica el nodo actual en el nodo ra´ız. Ver figura 8.46.
180
´ CAP´ITULO 8. ARBOL
Figura 8.46: removeSubTree - Caso 2 - paso 5
6. Se hace el recorrido del ´arbol por niveles (elegido de manera arbitraria), despu´es de eliminar el sub´arbol. Ver figura 8.47.
Figura 8.47: removeSubTree - Caso 2 - paso 6 A partir de la lista formada en el recorrido anterior, se obtiene el n´ umero de nodos del ´arbol. En este caso se obtiene un 5. Este valor se asigna al atributo size del ´arbol. Ver figura 8.48.
8.7. DETALLES DE LAS OPERACIONES
181
Figura 8.48: removeSubTree - Caso 2 - paso 7
7. Se ubica el nodo actual en el nodo se˜ nalado por temporal para ubicar adecuadamente la referencia current. Ver figura 8.49.
Figura 8.49: removeSubTree - Caso 2 - paso 8 Finalmente, se pone en true el atributo changed. removeLeaf Permite eliminar el nodo actual cuando es hoja. Se consideran dos casos: El nodo actual es el u ´nico nodo del ´arbol y el caso en el que hay m´as de un
182
´ CAP´ITULO 8. ARBOL
nodo en el ´arbol pero el nodo actual es hoja. Si el nodo actual es null o no es hoja, se lanza una excepci´on. Caso 1: El nodo actual es el u ´nico nodo del ´arbol. Ver precondici´on en la figura 8.50.
Figura 8.50: removeLeaf - Precondici´on - Caso 1 A continuaci´on se pueden ver los pasos necesarios para eliminar una hoja referenciada por el nodo actual, siendo el u ´nico nodo del ´arbol. 1. La referencia root se actualiza a null. Ver figura 8.51.
Figura 8.51: removeLeaf - Caso 1 - Paso 1
2. La referencia current se actualiza a null. Ver figura 8.52.
Figura 8.52: removeLeaf - Caso 1 - Paso 2 El nodo queda marcado autom´aticamente para ser eliminado por el recolector de basura de Java. Ver figura 8.53.
8.7. DETALLES DE LAS OPERACIONES
183
Figura 8.53: removeLeaf - Caso 1 - Recolector de basura (1) Despu´es de que el recolector de basura ha eliminado el nodo que no ten´ıa referencia externa, el ´arbol se puede ver como en la figura 8.54.
Figura 8.54: removeLeaf - Caso 1 - Recolector de basura (2)
3. Se actualiza a cero (0) el atributo size. Ver figura 8.55.
Figura 8.55: removeLeaf - Caso 1 - Paso 3 Luego, el atributo changed toma el valor de true. Caso 2: El nodo actual es hoja pero hay m´as de un nodo en el ´arbol. Ver precondici´on en la figura 8.56.
184
´ CAP´ITULO 8. ARBOL
Figura 8.56: removeLeaf - Precondici´on - Caso 2 A continuaci´on se pueden ver los pasos necesarios para eliminar una hoja referenciada por el nodo actual, cuando hay m´as de un nodo en el ´arbol. 1. Se obtiene el ´ındice del nodo actual como hijo de su padre. En el ejemplo se obtiene un 3. Ver figura 8.57.
Figura 8.57: removeLeaf - Caso 2 - Paso 1
2. Ubica el nodo actual como el padre del nodo actual, es decir, sube un nivel. Ver figura 8.58.
8.7. DETALLES DE LAS OPERACIONES
185
Figura 8.58: removeLeaf - Caso 2 - Paso 2 (1) Debido a que cada enlace es bidireccional, la imagen anterior es equivalente a la de la figura 8.59.
Figura 8.59: removeLeaf - Caso 2 - Paso 2 (2)
3. Se desconecta el puerto 3 (correspondiente al 織覺ndice obtenido en el paso 1). Ver figura 8.60.
186
´ CAP´ITULO 8. ARBOL
Figura 8.60: removeLeaf - Caso 2 - Paso 3 El nodo queda marcado autom´aticamente para ser eliminado por el recolector de basura de Java. Ver figura 8.61.
Figura 8.61: removeLeaf - Caso 2 - Recolector de basura (1) Despu´es de que el recolector de basura ha eliminado el nodo que no ten´ıa referencia externa, el ´arbol se puede ver como en la figura 8.62.
8.7. DETALLES DE LAS OPERACIONES
187
Figura 8.62: removeLeaf - Caso 2 - Recolector de basura (2)
4. Se disminuye en uno la cantidad de nodos del ´arbol. Ver figura 8.63.
Figura 8.63: removeLeaf - Caso 2 - Paso 4
Para terminar, el atributo changed toma el valor true.
8.7.3.
An´ alisis
Las operaciones de an´alisis permiten obtener informaci´on del ´arbol o de alg´ un nodo.
´ CAP´ITULO 8. ARBOL
188 currentHasSon
Recibe el ´ındice del hijo que se quiere verificar. Devuelve un valor de true o false de acuerdo a la existencia o no del hijo con el ´ındice especificado. Si el ´ındice es mayor o igual que el n´ umero de puertos del nodo actual se lanza una excepci´on. Suponga la precondici´on de la figura 8.64 y que desea verificar si existe el hijo con ´ındice 3. En este caso, se obtiene un true.
Figura 8.64: currentHasSon - Precondici´on (1) Si se desea verificar el hijo con ´ındice 4, se lanza una excepci´on, porque el nodo actual tiene cuatro puertos, por lo que el n´ umero posible de hijos es 3. Ahora, si el n´ umero de puertos del nodo actual hace posible que tuviera el hijo con el ´ındice especificado, simplemente se verifica si el nodo actual est´a conectado o no en ese puerto. Suponga que desea verificar si existe el hijo con ´ındice 2. Ver la figura 8.65.
Figura 8.65: currentHasSon - Precondici´on (2) En este caso, retorna un false porque el puerto 2 est´a desconectado. Si se verificara el hijo con ´ındice 1, retornar´ıa un valor true.
8.7. DETALLES DE LAS OPERACIONES
189
get Permite obtener la referencia al objeto, almacenada en el campo de datos del nodo actual. Ver precondici´on en la figura 8.66.
Figura 8.66: get - Precondici´on En este caso obtiene una referencia al objeto de tipo Character cuyo contenido es la letra C. getSize Permite obtener el n´ umero de nodos del ´arbol. Ver una posible precondici´on en la figura 8.67.
Figura 8.67: getSize - Precondici´on En este caso, se obtiene un 4, correspondiente al n´ umero de nodos del ´arbol. getIndex Determina el ´ındice que le corresponde al nodo actual como hijo de su padre. En caso de que el nodo actual sea el nodo ra´ız del ´arbol, retorna el valor -1. Suponga la precondici´on de la figura 8.68.
190
´ CAP´ITULO 8. ARBOL
Figura 8.68: getIndex - Precondici´on (1)
En este caso, se obtiene un 2 como ´ındice del nodo actual con respecto a la disposici´on de los puertos en el padre. Ahora, considere la precondici´on de la figura 8.69.
Figura 8.69: getIndex - Precondici´on (2) En este caso, se obtiene un valor -1 porque el nodo actual es el nodo ra´ız. getHeight Determina la altura del nodo actual. Si el ´arbol est´a vac´ıo, retorna -1. Suponga la precondici´on de la figura 8.70.
8.7. DETALLES DE LAS OPERACIONES
191
Figura 8.70: getHeight - Precondici´on (1)
En este caso, se obtiene un 2 como altura del nodo actual. Ahora, considere la precondici´on de la figura 8.71.
Figura 8.71: getHeight - Precondici´on (2) En este caso, se obtiene un valor -1 porque el ´arbol est´a vac´ıo. getWeight Determina el peso del nodo actual. Si el ´arbol est´a vac´ıo, retorna 0. Suponga la precondici´on de la figura 8.72.
192
´ CAP´ITULO 8. ARBOL
Figura 8.72: getWeight - Precondici´on (1) En este caso, se obtiene un 5 porque ese es el n´ umero de descendientes del nodo actual. Ahora, considere la precondici´on de la figura 8.73.
Figura 8.73: getWeight - Precondici´on (2) En este caso, se obtiene un valor 0 porque el nodo actual es hoja. Por otra parte, si el ´arbol est´a vac´ıo, tambi´en retorna un 0. Ver precondici´on de la figura 8.74.
8.7. DETALLES DE LAS OPERACIONES
193
Figura 8.74: getWeight - Precondici´on (3) En este caso, se obtiene un valor 0 porque el ´arbol est´a vac´ıo y no tiene descendientes. getLeastNumberPort Retorna el puerto libre con ´ındice menor del nodo actual. En el caso del ´arbol de la figura 8.75, esta operaci´on retorna 3, porque los puertos 1 y 2 est´an ocupados.
Figura 8.75: getLeastNumberPort - Precondici´on (1) Ahora, si se considera el ´arbol de la figura 8.76, esta operaci´on retorna 2, porque corresponde al puerto libre con ´ındice menor. No olvide que el puerto con ´ındice 0 est´a reservado para conectar a un nodo con su padre.
´ CAP´ITULO 8. ARBOL
194
Figura 8.76: getLeastNumberPort - Precondici´on (2)
isValidCurrent Permite saber si el nodo actual es v´alido o no. Retorna un valor false o true. Suponga la precondici´on de la figura 8.77.
Figura 8.77: isValidCurrent - Precondici´on (1)
En este caso, el nodo actual es v´alido, por lo tanto se obtiene un valor true. Ahora, considere la precondici´on de la figura 8.78.
Figura 8.78: isValidCurrent - Precondici´on (2)
En este caso, se obtiene un valor false porque el nodo actual es null.
8.7. DETALLES DE LAS OPERACIONES
195
isEmpty Permite saber si el ´arbol est´a vac´ıo o no. Retorna un valor false o true. Suponga la precondici´on de la figura 8.79.
Figura 8.79: isEmpty - Precondici´on (1) En este caso, el arbol est´a vac´ıo, por lo tanto se obtiene un valor true. Ahora, considere la precondici´on de la figura 8.80.
Figura 8.80: isEmpty - Precondici´on (2) En este caso, se obtiene un valor false porque el ´arbol no est´a vac´ıo. currentIsLeaf Permite saber si el nodo actual es hoja o no. Hace un recorrido por todos sus puertos, excepto el puerto PARENT. Si alguno de los puertos est´a conectado, se obtiene un false. Si logra terminar el recorrido, sin encontrar alg´ un nodo conectado, obtiene un true. Suponga la precondici´on de la figura 8.81.
´ CAP´ITULO 8. ARBOL
196
Figura 8.81: currentIsLeaf - Precondici´on (1) En este caso, el nodo actual no es hoja, por lo tanto se obtiene un valor false. Ahora, considere la precondici´on de la figura 8.82.
Figura 8.82: currentIsLeaf - Precondici´on (2) En este caso, se obtiene un valor true porque el nodo actual es hoja. currentIsRoot Retorna un valor false o true dependiendo de la situaci´on del nodo actual. Si el nodo actual es el nodo ra´ız, retorna un valor true. En otro caso, retorna un valor false. Suponga la precondici´on de la figura 8.83.
8.7. DETALLES DE LAS OPERACIONES
197
Figura 8.83: currentIsRoot - Precondici´on (1)
En este caso, se obtiene un true porque el nodo actual es el nodo ra´ız. Ahora, considere la precondici´on de la figura 8.84.
Figura 8.84: currentIsRoot - Precondici´on (2)
En este caso, se obtiene un valor false porque el nodo actual no es el nodo ra´ız. preOrder Permite obtener una lista enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol en el recorrido preorden. Este recorrido inicia en el nodo actual. El recorrido preorden se realiza de la siguiente manera: primero se procesa el nodo ra´ız del sub´arbol y a continuaci´on se hace un recorrido preorden de cada uno de sus hijos en orden ascendente desde el hijo con ´ındice 1. Procesar el nodo indica recuperar la referencia al objeto, almacenada en el nodo ra´ız del sub´arbol para adicionarla a la lista. Ver una posible precondici´on en la figura 8.85.
198
´ CAP´ITULO 8. ARBOL
Figura 8.85: Precondici´on - recorridos
El resultado del recorrido preorden queda almacenado en una lista. Para el ejemplo, la lista resultado se puede ver en la figura 8.86.
Figura 8.86: preOrder - Poscondici´on
postOrder Permite obtener una lista enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol en el recorrido postorden. Este recorrido inicia en el nodo actual. El recorrido postorden se realiza de la siguiente manera: primero se hace un recorrido postorden de cada uno de los hijos del nodo ra´ız del sub´arbol que se quiere examinar, en orden ascendente desde el hijo con ´ındice 1. A continuaci´on se procesa el nodo ra´ız. Procesar el nodo indica recuperar la
8.7. DETALLES DE LAS OPERACIONES
199
referencia al objeto, almacenada en el nodo ra´ız del sub´arbol para adicionarla a la lista. Ver una posible precondici´on en la figura 8.85. El resultado del recorrido postorden queda almacenado en una lista. Para el ejemplo, la lista resultado se puede ver en la figura 8.87.
Figura 8.87: postOrder - Poscondici´on
levels Permite obtener una lista enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol en el recorrido por niveles. Este recorrido inicia en el nodo actual. El recorrido por niveles se realiza de la siguiente manera: primero se procesa el nodo ra´ız, el cual corresponde al nivel cero. A continuaci´on se procesan los hijos del nodo ra´ız del sub´arbol que se quiere examinar, es decir, los nodos con nivel uno. Luego los que tienen nivel dos y as´ı sucesivamente. Ver una posible precondici´on en la figura 8.85. El resultado del recorrido por niveles queda almacenado en una lista. Para el ejemplo, la lista resultado se puede ver en la figura 8.88.
Figura 8.88: levels - Poscondici´on
inOrder Permite obtener una lista enlazada cuyo contenido sea la informaci´on de los nodos del ´arbol en el recorrido in-orden. Este recorrido inicia en el nodo actual. Este recorrido solo se aplica a los ´arboles binarios, es decir, a los ´arboles que tienen m´aximo dos hijos. El recorrido in-orden se realiza de la siguiente manera: primero se procesa el hijo izquierdo en recorrido in-orden, luego el nodo ra´ız y a continuaci´on
200
´ CAP´ITULO 8. ARBOL
se hace un recorrido in-orden al hijo derecho. Procesar el nodo indica recuperar la referencia al objeto, almacenada en uno de los nodos del ´arbol para adicionarla a la lista. Ver una posible precondici´on en la figura 8.89.
Figura 8.89: inOrder - Precondici´on El resultado del recorrido in-orden queda almacenado en una lista. Para el ejemplo, la lista resultado se puede ver en la figura 8.90.
Figura 8.90: inOrder - Poscondici´on
getChanged No recibe ning´ un par´ametro, retorna el valor del atributo changed. toString Esta operaci´on construye una cadena con el contenido del ´arbol en el recorrido por niveles. Este recorrido se eligi´o de manera arbitraria. Una posible precondici´on se puede ver en la figura 8.91.
8.7. DETALLES DE LAS OPERACIONES
201
Figura 8.91: toString - Precondici´on
La cadena resultante con los valores de los nodos del ´arbol es: A B C D E F
8.7.4.
Localizaci´ on
Las operaciones de localizaci´on permiten posicionar el nodo actual en el nodo ra´ız, en el padre del nodo actual o en alguno de sus hijos. goRoot Modifica la referencia del nodo actual para que se˜ nale ahora al nodo ra´ız del ´arbol. Ver una posible precondici´on en las figura 8.92.
202
´ CAP´ITULO 8. ARBOL
Figura 8.92: goRoot - Precondici´on La poscondici´on correspondiente se puede ver en la figura 8.93.
Figura 8.93: goRoot - Poscondici´on
goParent Modifica la referencia del nodo actual para que se˜ nale ahora al padre del nodo actual. Si existe el padre del nodo actual, el nodo actual subir´a un nivel. Si no existe, se lanza una excepci´on. Ver una posible precondici´on en las figura 8.94.
8.7. DETALLES DE LAS OPERACIONES
203
Figura 8.94: goParent - Precondici´on
La poscondici´on correspondiente se puede ver en la figura 8.95.
Figura 8.95: goParent - Poscondici´on
goSon Recibe como par´ametro el ´ındice correspondiente a un hijo del nodo actual. Si el hijo existe, el nodo actual pasa a ser el hijo especificado. Si no existe, se lanza una excepci´on. Ver una posible precondici´on en la figura 8.96 y suponga que desea ir al hijo 2.
´ CAP´ITULO 8. ARBOL
204
Figura 8.96: goSon - Precondici´on La poscondici´on correspondiente se puede ver en la figura 8.97.
Figura 8.97: goSon - Poscondici´on
8.7.5.
Persistencia
Las operaciones de persistencia permiten almacenar el estado del ´arbol en un medio persistente (archivo). De igual manera, se permite recuperar un ´arbol desde un archivo de datos. save: Almacena en un archivo el contenido del ´arbol y pone en false el valor del atributo changed. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Puede disparar una excepci´on si el archivo no puede ser creado o no se puede escribir en ´el. load: Carga a la memoria el ´arbol completo. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Si no existe el archivo o no se puede leer, se dispara una excepci´on. Ver figura 8.98.
8.7. DETALLES DE LAS OPERACIONES
Figura 8.98: save y load
205
206
´ CAP´ITULO 8. ARBOL
9
Otras clases de ´arboles 9.1.
Arbol binario de b´ usqueda
El ´arbol binario de b´ usqueda es una estructura de datos que permite almacenar n´ umeros (generalmente enteros) de una forma ordenada. Los elementos almacenados en el campo de datos de cada nodo del ´arbol se denominan claves o llaves. Para cada nodo del ´arbol binario de b´ usqueda, el valor de cada una de las claves del sub´arbol izquierdo es menor que la clave del nodo. De igual manera, el valor de cada una de las claves del sub´arbol derecho es mayor que la clave del nodo. Un ejemplo de un ´arbol binario de b´ usqueda se puede ver en la figura 9.1. Un ´arbol binario es de b´ usqueda si al aplicarle el recorrido inorden se obtiene una lista con las claves, ordenada de menor a mayor. El ´arbol binario de b´ usqueda se complementa con el algoritmo de b´ usqueda binaria, el cual consiste en recorrer el ´arbol de forma descendente desde el nodo ra´ız hasta la clave que se est´a buscando. En cada iteraci´on se compara la clave que se est´a buscando con la que se encuentra almacenada en el nodo actual. Si la clave que se busca es mayor, el nodo actual es el hijo derecho
208
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
´ Figura 9.1: Arbol binario de b´ usqueda
del nodo actual. Si es menor, el nodo actual es el hijo izquierdo del nodo actual. El m´etodo termina cuando la clave es encontrada porque es igual a la del nodo actual. Si en alg´ un momento no es posible modificar la posici´on del nodo actual como el hijo derecho o izquierdo, significa que la clave buscada no existe en el ´arbol. Por ejemplo, de acuerdo con la figura 9.1, si se desea buscar la clave 10, lo encuentra en la primera comparaci´on. Si desea buscar la clave 3, se realizan varias comparaciones y el nodo actual va cambiando su posici´on acerc´andose a la clave que se est´a buscando. La clave del nodo actual es 10 y se busca 3. Como 3 es menor que 10, el nodo actual pasa a ser el hijo izquierdo del actual. Es decir, el nodo actual es el que tiene la clave 6. Como 3 es menor que 6, el nodo actual pasa a ser el hijo izquierdo del actual. Es decir, el nodo actual es el que tiene la clave 4. Como 3 es menor que 4, el nodo actual pasa a ser el hijo izquierdo del actual. Es decir, el nodo actual es el que tiene la clave 2. Ahora, el 3 es mayor que el 2 y entonces el nodo actual es el hijo derecho del actual. Es decir, el nodo actual es el que tiene la clave 3. Finalmente, el nodo actual tiene la clave que se est´a buscando, lo que quiere decir que la clave s´ı est´a en el ´arbol.
´ 9.1. ARBOL BINARIO DE BUSQUEDA
209
Por otra parte, si la clave que se busca es el 14, otra vez el nodo actual inicia en el nodo ra´ız con clave 10. Como 14 es mayor que 10, el nodo actual es el hijo derecho del nodo actual, se decir, el que tiene la clave 15. Luego se compara el 14 con el 15 por lo que el hijo actual es el 12, el hijo izquierdo del nodo actual. Al comparar el 12 con el 14, el nodo actual deber´ıa ser el hijo derecho del nodo actual, pero como no existe, se llega a la conclusi´on de que la clave que se busca no existe en el ´arbol. Con respecto a las claves repetidas se puede dar el caso de que sean aceptadas o no. En el caso de que sean permitidas, simplemente se realiza la modificaci´on al momento de las comparaciones, dejando las claves mayores o iguales a la de la clave del nodo actual. Otra variaci´on podr´ıa ser acumular un contador con el n´ umero de repeticiones de cada clave.
9.1.1.
Operaciones del ´ arbol binario de b´ usqueda
Insertar Para insertar una clave en un ´arbol binario de b´ usqueda sin repeticiones, se debe proceder de la siguiente manera: Si el ´arbol est´a vac´ıo, se crea el nodo ra´ız del ´arbol. Si el ´arbol no est´a vac´ıo, existen tres posibles casos: • Caso 1: la nueva clave es igual a la del nodo ra´ız, entonces se descarta. • Caso 2: Si la nueva clave es menor que la del nodo ra´ız, el nodo actual pasa a ser el hijo izquierdo del nodo actual (si existe). Si el hijo izquierdo del nodo actual no existe, se crea el hijo izquierdo con la nueva clave.
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
210
• Caso 3: Si la nueva clave es mayor que la del nodo ra´ız, el nodo actual pasa a ser el hijo derecho del nodo actual (si existe). Si el hijo derecho del nodo actual no existe, se crea el hijo derecho con la nueva clave. Por ejemplo, insertar en un ´arbol binario de b´ usqueda la siguiente secuencia de claves: 10
6
15
12
8
7
4
18
16
20
Inicialmente el ´arbol est´a vac´ıo. Entonces se crea un nuevo nodo con la clave 10. El ´arbol se puede ver como en la figura 9.2.
Figura 9.2: Insertar una clave en un ´arbol binario de b´ usqueda - 1 Cuando se va a insertar el 6, debe quedar a la izquierda del 10. Ver figura 9.3.
Figura 9.3: Insertar una clave en un ´arbol binario de b´ usqueda - 2
La clave 15 debe quedar a la derecha del 10. Ver figura 9.4.
Figura 9.4: Insertar una clave en un ´arbol binario de b´ usqueda - 3
´ 9.1. ARBOL BINARIO DE BUSQUEDA
211
Al insertar el 12, debe quedar a la derecha del 10 pero al a izquierda del 15. Ver figura 9.5.
Figura 9.5: Insertar una clave en un ´arbol binario de b´ usqueda - 4 Al insertar el 8, debe quedar a la izquierda del 10 pero a la derecha del 6. Ver figura 9.6.
Figura 9.6: Insertar una clave en un ´arbol binario de b´ usqueda - 5 Despu´es de insertar el 7, a la izquierda del 10, a la derecha del 6 y a la izquierda del 8; y despu´es de insertar el 4 a la izquierda del 10 y a la izquierda del 6. Ver figura 9.7.
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
212
Figura 9.7: Insertar una clave en un ´arbol binario de b´ usqueda - 6 Luego se insertan en el ´arbol las claves 18, a la derecha del 15; 16, a la izquierda del 18 y el 20, a la derecha del 18. Ver figura 9.8.
Figura 9.8: Insertar una clave en un ´arbol binario de b´ usqueda - 7
Buscar La b´ usqueda de una clave en un ´arbol binario de b´ usqueda se conoce como b´ usqueda binaria. El procedimiento es bastante simple, consiste en retornar un valor true si la clave est´a en el ´arbol o false en caso contrario. Procedimiento: Si el ´arbol est´a vac´ıo, retornar false. El nodo actual se˜ nala el nodo ra´ız.
´ 9.1. ARBOL BINARIO DE BUSQUEDA
213
Si el ´arbol no est´a vac´ıo, se inicia un ciclo infinito, del cual sale cuando tenga un resultado false o true. Si la clave en el nodo actual concide con la clave buscada, retorna true. Si no, si la clave buscada es mayor que la del nodo actual, el nodo actual pasa a ser el hijo derecho del nodo actual (si existe) y pasa a la siguiente iteraci´on. Si no existe, retorna false. Si la clave en buscada es menor que la del nodo actual, el nodo actual pasa a ser el hijo izquierdo del nodo actual (si existe) y pasa a la siguiente iteraci´on. Si no existe, retorna false. Eliminar La operaci´on eliminar es un poco m´as complicada porque no es suficiente con buscar la clave que se desea eliminar. Es necesario considerar varias alternativas de manera que el ´arbol permanezca ordenado, las cuales dependen del n´ umero de hijos del nodo que se va a eliminar. Si se va a eliminar una hoja del ´arbol, no hay que tener ninguna consideraci´on adicional y se puede eliminar. Si se va a eliminar un nodo que tiene un solo hijo, es suficiente con actualizar los enlaces entre los nodos abuelo y nieto (padre e hijo del nodo eliminado). Por ejemplo, dado el ´arbol de la figura 9.9, eliminar la clave 8.
Figura 9.9: Eliminar una clave en un ´arbol binario de b´ usqueda - 1 Para asegurarse de que el ´arbol contin´ ue ordenado, es necesario redefinir los enlaces entre los nodos cuyas claves son 6 y 7. Ver figura 9.10.
214
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
Figura 9.10: Eliminar una clave en un ´arbol binario de b´ usqueda - 2
Cuando se desea eliminar un nodo que tiene dos hijos el procedimiento es un poco diferente. En este caso, se debe reemplazar la clave del nodo a eliminar con la clave del menor elemento del sub´arbol derecho. Luego, se debe eliminar el menor elemento del sub´arbol derecho, que de antemano se sabe que es hoja o no tiene hijo izquierdo. Por ejemplo, eliminar la clave 10. Ver figura 9.11.
Figura 9.11: Eliminar una clave en un ´arbol binario de b´ usqueda - 3 El primer paso es reemplazar la clave 10 por 12, que es el menor elemento del sub´arbol derecho. Ver figura 9.12.
´ 9.1. ARBOL BINARIO DE BUSQUEDA
215
Figura 9.12: Eliminar una clave en un ´arbol binario de b´ usqueda - 4
A continuaci´on se elimina la clave 12, el hijo izquierdo del 15, que como se sabe, no tiene hijo izquierdo, y se ajustan los enlaces entre las claves 15 y 14. Ver figura 9.13.
Figura 9.13: Eliminar una clave en un ´arbol binario de b´ usqueda - 5
9.1.2.
C´ odigo fuente
Insertar una clave public void insertarNumero ( int numero ) throws Exception { int auxiliar; arbol.goRoot ( );
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
216
if ( arbol.getSize ( ) == 0 ) { arbol.addRoot ( new Integer ( numero ) ); } while ( true ) { auxiliar = ( ( Integer ) arbol.get ( ) ).intValue ( ) ; if ( numero > auxiliar ) { if ( arbol.currentHasSon ( RIGHT ) ) { arbol.goSon ( RIGHT ); } else { arbol.addSon ( new Integer ( numero ), RIGHT ); break; } } else { if ( numero < auxiliar ) { if ( arbol.currentHasSon ( LEFT ) ) { arbol.goSon ( LEFT ); } else { arbol.addSon ( new Integer ( numero ), LEFT ); break; } } else { break; } } } }
´ 9.1. ARBOL BINARIO DE BUSQUEDA B´ usqueda binaria public boolean buscarNumero ( int numero ) throws Exception { int auxiliar; arbol.goRoot ( ); if ( arbol.getSize ( ) == 0 ) { return false; } while ( true ) { auxiliar = ( ( Integer ) arbol.get ( ) ).intValue ( ) ; if ( numero == auxiliar ) { return true; } else { if ( numero > auxiliar ) { if ( arbol.currentHasSon ( RIGHT ) ) { arbol.goSon ( RIGHT ); } else { return false; } } else { if ( arbol.currentHasSon ( LEFT ) ) { arbol.goSon ( LEFT ); } else { return false; } } }
217
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
218 } }
9.2.
´ Arbol AVL
AVL toma el nombre de las iniciales de sus dos creadores, Adelson-Velski y Landis. Un ´arbol AVL es una clase de ´arbol binario de b´ usqueda que se caracteriza por mantener el equilibrio entre las ramas izquierda y derecha del ´arbol, con el fin de mejorar el desempe˜ no general en el proceso de b´ usqueda de claves. En un ´arbol binario de b´ usqueda, la estructura del ´arbol depende del orden en el cual las claves han sido a˜ nadidas al ´arbol, por lo que puede ocurrir que las alturas de sus ramas sean desproporcionadas. En un ´arbol AVL, la diferencia entre las alturas de las ramas izquierda y derecha no puede ser mayor que 1 ni menor que -1, para todos los nodos del ´arbol. Un ejemplo de un ´arbol AVL se puede ver en la figura 9.14.
Figura 9.14: Ejemplo de un ´arbol AVL
´ 9.2. ARBOL AVL
219
Un ejemplo de un ´arbol binario de b´ usqueda que no cumple con la condici´on de equilibrio se puede ver en la figura 9.15.
Figura 9.15: Ejemplo de un ´arbol binario de b´ usqueda no equilibrado
9.2.1.
Operaciones en un ´ arbol AVL
Las operaciones de un ´arbol AVL son equivalentes a las operaciones de un ´arbol binario de b´ usqueda. El paso adicional ocurre cuando al insertar o eliminar un nodo del ´arbol es posible que algunos nodos pierdan la propiedad de equilibrio, raz´on por la cual es necesario realizar algunos cambios en los enlaces entre los nodos con el fin de recuperar el equilibrio. A continuaci´on se considera la p´erdida de equilibrio en la operaci´on insertar. Se puede perder el equilibrio en un nodo x de un ´arbol AVL por la inserci´on de un nodo en una de las cuatro situaciones. Caso 1: Insertar una clave en la rama izquierda del hijo izquierdo de x. Caso 2: Insertar una clave en la rama derecha del hijo izquierdo de x. Caso 3: Insertar una clave en la rama izquierda del hijo derecho de x. Caso 4: Insertar una clave en la rama derecha del hijo derecho de x.
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
220
En los casos 1 y 4, el equilibrio se recupera con una operaci´on llamada rotaci´on simple, la cual consiste en el intercambio de nivel entre padres e hijos, manteniendo el orden de los nodos en el ´arbol. Para los casos 2 y 3, se requiere una operaci´on llamada rotaci´on doble, la cual es un poco m´as compleja porque en ella intervienen tres nodos. Sin embargo, se sirve de las rotaciones simples para llevar a cabo el trabajo. Rotaci´ on simple a derecha Para resolver el caso 1, es necesario llevar a cabo una rotaci´on simple a derecha. Es necesario pasar dos par´ametros: El nodo x, que corresponde al nodo m´as alto donde se desequilibra el ´arbol El hijo izquierdo del nodo x, llamado xI. El procedimiento consiste en: El hijo derecho de xI pasa a ser el hijo izquierdo del nodo x. El nodo x pasa a ser el hijo derecho del nodo xI. Ejemplo: Al insertar la clave 2, se ha perdido el equilibrio a partir de la clave 10. Ver figura 9.16.
´ 9.2. ARBOL AVL
221
Figura 9.16: Ejemplo de una rotaci´on simple a derecha Al ejecutar el paso 1, el hijo derecho del nodo xI pasa a ser el hijo izquierdo del nodo x. Ver figura 9.17.
Figura 9.17: Ejemplo de una rotaci´on simple a derecha - 1 El paso 2 consiste en hacer que el nodo x pase a ser el hijo derecho del nodo xI. Ver figura 9.18.
Figura 9.18: Ejemplo de una rotaci´on simple a derecha - 2
222
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
Rotaci´ on simple a izquierda Para resolver el caso 4, es necesario llevar a cabo una rotaci´on simple a izquierda, la cual es sim´etrica con respecto al caso 1. Es necesario pasar dos par´ametros: El nodo x, que corresponde al nodo m´as alto donde se desequilibra el ´arbol El hijo derecho del nodo x, llamado xD. El procedimiento consiste en: El hijo izquierdo de xD pasa a ser el hijo derecho del nodo x. El nodo x pasa a ser el hijo izquierdo del nodo xD. Rotaci´ on doble a derecha Para resolver el caso 2, es necesario llevar a cabo una rotaci´on doble a derecha. Es necesario pasar tres par´ametros: El nodo x, que corresponde al nodo m´as alto donde se desequilibra el ´arbol El hijo izquierdo del nodo x, llamado xI. El hijo derecho de xI, llamado xID. El procedimiento consiste en: Realizar una rotaci´on simple a izquierda pasando por par´ametro xI y xID. Realizar una rotaci´on simple a derecha pasando por par´ametro x y xID. Adicionalmente es necesario recuperar el enlace entre el nodo x y su hijo derecho. Ejemplo: Insertar la clave 9. Observe que se ha perdido el equilibrio a partir de la clave 10. Ver figura 9.19.
´ 9.2. ARBOL AVL
223
Figura 9.19: Ejemplo de una rotaci´on doble a derecha Al ejecutar el paso 1, se debe realizar una rotaci´on simple a izquierda pasando por par´ametro xI y xID. Ver figura 9.20.
Figura 9.20: Ejemplo de una rotaci´on doble a derecha - 1 El paso 2 consiste en hacer una rotaci´on simple a derecha pasando por par´ametro x y xID. Ver figura 9.21.
Figura 9.21: Ejemplo de una rotaci´on doble a derecha - 2
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
224
Rotaci´ on doble a izquierda Para resolver el caso 3, es necesario llevar a cabo una rotaci´on doble a izquierda la cual es sim´etrica con respecto al caso 2. Es necesario pasar tres par´ametros: El nodo x, que corresponde al nodo m´as alto donde se desequilibra el ´arbol El hijo derecho del nodo x, llamado xD. El hijo izquierdo de xD, llamado xDI. El procedimiento consiste en: Realizar una rotaci´on simple a izquierda pasando por par´ametro xD y xDI. Realizar una rotaci´on simple a derecha pasando por par´ametro x y xID. Adicionalmente es necesario recuperar el enlace entre el nodo x y su hijo derecho.
9.2.2.
C´ odigo fuente
Rotaci´ on simple a derecha public static void rotacionSimpleDerecha ( Node x, Node xI ) throws Exception { if ( xI.isLink ( RIGHT ) ) { x.link ( xI.whoLink ( RIGHT ), LEFT ); } else { x.unLink ( LEFT ); }
´ 9.2. ARBOL AVL if ( xI.isLink ( RIGHT ) ) { xI.whoLink ( RIGHT ).link ( x, PARENT ); } xI.link ( x, RIGHT ); if ( x.isLink ( PARENT ) ) { xI.link ( x.whoLink ( PARENT ), PARENT ); } else { xI.unLink ( PARENT ); } if ( x.isLink ( PARENT ) ) { x.whoLink ( PARENT ).link ( xI, LEFT ); } x.link ( xI, PARENT ); }
Rotaci´ on simple a izquierda public static void rotacionSimpleIzquierda ( Node x, Node xD ) throws Exception { if ( xD.isLink ( LEFT ) ) { x.link ( xD.whoLink ( LEFT ), RIGHT ); } else { x.unLink ( RIGHT ); } if ( xD.isLink ( LEFT ) ) { xD.whoLink ( LEFT ).link ( x, PARENT ); } xD.link ( x, LEFT );
225
226
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES if ( x.isLink ( PARENT ) ) { xD.link ( x.whoLink ( PARENT ), PARENT ); } else { xD.unLink ( PARENT ); } if ( x.isLink ( PARENT ) ) { x.whoLink ( PARENT ).link ( xD, RIGHT ); } x.link ( xD, PARENT );
}
Rotaci´ on doble a derecha public static void rotacionDobleDerecha ( Node x, Node xI, Node xID ) throws Exception { Node temporal; if ( x.isLink ( RIGHT ) ) { temporal = x.whoLink ( RIGHT ); } else { temporal = null; } rotacionSimpleIzquierda ( xI, xID ); rotacionSimpleDerecha ( x, xID ); if ( temporal != null ) { x.link ( temporal, RIGHT ); } else {
9.3. ARBOLES B
227
if ( x.isLink ( RIGHT ) ) { x.unLink ( RIGHT ); } } }
Rotaci´ on doble a izquierda public static void rotacionDobleIzquierda ( Node x, Node xD, Node xDI ) throws Exception { Node temporal; if ( x.isLink ( LEFT ) ) { temporal = x.whoLink ( LEFT ); } else { temporal = null; } rotacionSimpleDerecha ( xD, xDI ); rotacionSimpleIzquierda ( x, xDI ); if ( temporal != null ) { x.link ( temporal, LEFT ); } else { if ( x.isLink ( LEFT ) ) { x.unLink ( LEFT ); } } }
9.3.
Arboles B
De forma similar al ´arbol binario de b´ usqueda, existen ´arboles en los cuales cada nodo puede tener m´as de dos hijos, donde cada una de las ramas se
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
228 encuentra ordenada.
Los ´arboles estudiados hasta el momento, tienen su mayor aplicaci´on en el manejo de datos en memoria principal. Sin embargo, en algunas ocasiones puede tenerse una gran cantidad de datos lo que hace necesario que se almacenen directamente en disco. Los ´arboles multicamino se utilizan en la b´ usqueda de claves cuando los datos se encuentran almacenados en disco y se utilizan con el fin de minimizar los accesos al disco debido a la gran cantidad de tiempo que requieren. Entre los ´arboles multicamino m´as conocidos se encuentran los ´arboles B y los ´arboles B+. Los ´arboles B son estructuras de datos formadas por p´aginas, cada una de las cuales tiene un arreglo de m´aximo n claves distintas, ordenadas de menor a mayor. Tambi´en tienen un arreglo de m´aximo n + 1 referencias a otras p´aginas. En lugar de arreglos, podr´ıan utilizar listas enlazadas. Un atributo almacena el n´ umero de claves que se tienen guardadas en el arreglo de claves. Con este valor se puede conocer el n´ umero de referencias v´alidas a otras p´aginas. El orden de un ´arbol B es n / 2. Un ´arbol B puede tener orden 1, 2, 3, 4, .... Es decir, el arreglo de p´aginas siempre tiene un n´ umero par como capacidad m´axima. Por ejemplo, un ´arbol B de orden 2 tiene p´aginas de m´aximo 4 claves y 5 referencias a otras p´aginas. El orden del ´arbol B tambi´en sirve para conocer el n´ umero m´ınimo de claves que en un momento dado puede tener cualquier p´agina diferente de la ra´ız. Por ejemplo, en la figura 9.22 se puede ver un ´arbol B.
Figura 9.22: Ejemplo de un ´arbol B En un ´arbol B, todas las hojas deben estar al mismo nivel, con el fin de garantizar que el ´arbol se mantiene con la altura m´ınima posible.
9.3. ARBOLES B
9.3.1.
229
Operaciones
Las operaciones b´asicas para un ´arbol B son insertar una clave, eliminar una clave, buscar una clave y recorrer el ´arbol B. Insertar una clave Para dar una idea del procedimiento a seguir cuando sea necesario insertar una clave, se va a realizar el siguiente ejemplo. Insertar las siguientes claves en un ´arbol B de orden 2. 75 31
18 43
39 4
42 31
7 52
15 14
35 61
29 24
43 91
58 66
12 34
Un ´arbol B de orden 2 tiene p´aginas de m´ınimo dos y m´aximo cuatro claves. Insertar la clave 75 El ´arbol inicia vac´ıo. Luego, la clave 75 cabe en la p´agina ra´ız. Ver figura 9.23.
Figura 9.23: Insertar una clave en un ´arbol B - 1
Insertar las claves 18, 39 y 42, caben perfectamente en la p´agina ra´ız, ordenadas de menor a mayor. Observe la posici´on de la clave 75. Ver figura 9.24.
Figura 9.24: Insertar una clave en un ´arbol B - 2
Insertar la clave 7. En este caso, la clave no cabe en la p´agina ra´ız, por lo que se debe dividir en tres p´aginas. Se debe encontrar la clave que debe ir a la p´agina ra´ız (exactamente la de la mitad), luego de ordenar las cinco claves. 7 18 39 42 75
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
230
Las claves 7 y 18 pasan a la p´agina hija 1 de la p´agina ra´ız. Las claves 42 y 75 pasan a la p´agina hija 2 y la clave 39 pasa a ser la u ´nica clave de la p´agina ra´ız. Ver figura 9.25.
Figura 9.25: Insertar una clave en un ´arbol B - 3 Insertar las claves 15 y 35. En este caso caben perfectamente en la p´agina de la izquierda. Se deben ordenar las claves de menor a mayor. Ver figura 9.26.
Figura 9.26: Insertar una clave en un ´arbol B - 4 Insertar la clave 29. Por el valor deber´ıa almacenarse en la p´agina de la izquierda pero no hay espacio, por lo que debe elegirse la clave del centro y subirla a la p´agina ra´ız. 7 15 18 29 35 Las claves 7 y 15 pasan formar la p´agina hija 1, las claves 29 y 35 pasan a formar la p´agina hija 2 y las claves 42 y 75 se desplazan a la p´agina hija 3. Ver figura 9.27.
9.3. ARBOLES B
231
Figura 9.27: Insertar una clave en un ´arbol B - 5
Insertar las claves 43 y 58. Caben perfectamente en la p´agina hija 3, reordenando las claves. Ver figura 9.28.
Figura 9.28: Insertar una clave en un ´arbol B - 6
Insertar las 12, 31, 43, y 4. Las claves 12 y 4, caben en la p´agina hija 1. La clave 31 cabe en la p´agina hija 2 y la clave 43 no se acepta por estar repetida. Se deben reordenar las claves en las p´aginas hijas 1 y 2. Ver figura 9.29.
Figura 9.29: Insertar una clave en un ´arbol B - 7
Insertar las claves 31 y 52. La clave 31 no se acepta por estar repetida. La clave 52 debe ubicarse en la p´agina hija 3. Como no hay espacio para ella, se debe encontrar la clave del centro para subirla a la p´agina ra´ız. 42 43 52 58 75 Luego, se debe conformar la p´agina hija 3 con las claves 4 y 43 y la p´agina hija 4 con las claves 58 y 75. Ver figura 9.30.
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
232
Figura 9.30: Insertar una clave en un ´arbol B - 8
Insertar la clave 14. Debe ubicarse en la p´agina hija 1, pero como no hay espacio, se ordenan las claves y se determina que la clave 12 debe subirse a la p´agina ra´ız. Se debe crear una nueva p´agina hija 1 y p´agina hija 2—. Tambi´en se deben desplazar las otras tres p´aginas hijas existentes para formar las p´aginas hijas 3, 4 y 5. Ver figura 9.31.
Figura 9.31: Insertar una clave en un ´arbol B - 9
Insertar las claves 61, 24 y 91. Las claves 61 y 91 se ubican en la p´agina hija 5 y la clave 24 se ubica en la p´agina hija 3. Se deben ordenar las claves en el interior de cada p´agina. Ver figura 9.32.
Figura 9.32: Insertar una clave en un ´arbol B - 10
Insertar la clave 66. Deber´ıa ubicarse en la p´agina hija 5, pero como no hay espacio, se elige la clave del centro para subir a la p´agina ra´ız. 58 61 66 75 91
9.3. ARBOLES B
233
Debe subir la clave 66 a la p´agina ra´ız. El asunto es que tampoco hay espacio en la p´agina ra´ız para ubicar otra clave por lo que debe dividirse en dos, seleccionando la clave del centro para conformar la nueva p´agina ra´ız. 12 18 39 52 66 La nueva p´agina ra´ız tiene la clave 39. Esta p´agina ra´ız tiene dos p´aginas hijas, una con las claves 12 y 18, y otra con las claves 52 y 66. Ver figura 9.33.
Figura 9.33: Insertar una clave en un ´arbol B - 11
Insertar la clave 34. Debe ubicar se en la p´agina hija 3 de la p´agina hija 1. Como no hay espacio para ella, la clave 31 sube a la p´agina del nivel anterior. Ver figura 9.34.
Figura 9.34: Insertar una clave en un ´arbol B - 12
Eliminar una clave En el proceso de eliminar una clave de un ´arbol B, se debe cuidar de que ninguna p´agina tenga menos claves que el n´ umero especificado en el orden
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
234
del ´arbol, caso en el cual se deben unir p´aginas para que no se pierdan las caracter´ısticas de ´arbol B.
9.4.
´ Arboles B+
Un ´arbol B+ es un caso especial de los ´arboles B. Debido a su eficiente desempe˜ no se ha aplicado para el manejo de archivos de gran cantidad de informaci´on. A diferencia de un ´arbol B, en el ´arbol B+ todas las claves se ubican en el nivel m´as bajo del ´arbol. Las p´aginas internas almacenan los caminos que permiten encontrar las claves. En el ´arbol B+ se debe tener una referencia a la clave menor para que pueda recorrerse el ´arbol secuencialmente cuando sea necesario. Adem´as, al final de cada p´agina se debe tener una referencia que permita conectarla con el inicio de la siguiente. Un ´arbol B+ ocupa un poco m´as de espacio porque las claves de las p´aginas no terminales son duplicados que se utilizan como ´ındices para encontrar las claves en el nivel m´as bajo del ´arbol.
9.4.1.
Operaciones en un ´ arbol B+
Las operaciones b´asicas de un ´arbol B+ son las mismas que tiene un ´arbol B, es decir, insertar una clave, eliminar una clave, buscar una clave y recorrer el ´arbol.
Insertar una clave A diferencia de los ´arboles B, cuando se divide una p´agina en dos, en la p´agina de la izquierda se almacenan la mitad de las claves y en la derecha, la mitad de las claves mas la clave central, donde una copia pasa al nivel anterior, y se utiliza como ´ındice.
´ 9.4. ARBOLES B+
235
Eliminar una clave Si al eliminar una clave el n´ umero de claves en la p´agina no es inferior al n´ umero m´ınimo permitido, el proceso termina. Si por el contrario la p´agina est´a con un n´ umero insuficiente de claves, es necesario unir p´aginas. En el caso de que se elimine la clave que se encuentra duplicada en una p´agina interna, no es necesario suprimir la clave en las p´aginas no terminales porque siguen sirviendo como ´ındices de una manera correcta.
236
´ CAP´ITULO 9. OTRAS CLASES DE ARBOLES
10 Grafo
Un grafo es una estructura de datos formada por un conjunto de nodos o v´ertices y un conjunto de enlaces o aristas que conecta a los nodos. Si los enlaces tienen direcci´on o sentido, se dice que el grafo es dirigido, tambi´en llamado d´ıgrafo.
Si las aristas no tienen especificada la direcci´on, se dice que el grafo es no dirigido. Cuando no se especifica la direcci´on en un enlace se asume que es bidireccional.
Algunas veces, las aristas tienen un componente adicional llamado peso o costo, el cual representa el “costo de pasar”de un nodo a otro a trav´es de ese enlace. Esta informaci´on es importante para algunas aplicaciones.
CAP´ITULO 10. GRAFO
238
10.1.
Aplicaciones de un grafo
Los grafos pueden ser utilizados en innumerables aplicaciones de la realidad as´ı como en muchos problemas de las ciencias de la computaci´on. S´olo por menci´on se pueden considerar los siguientes: Representaci´on de las rutas de buses en el transporte p´ ublico de una ciudad, para determinar costos. Construcci´on de circuitos el´ectricos y electr´onicos al representar las conexiones entre los componentes. Control del tr´afico a´ereo, al representar las distancias, posiciones y velocidades de las distintas aeronaves. Difusi´on de paquetes en una red de computadores, al observar c´omo los paquetes “viajan”entre los dispositivos que componen la red. Modelado de software, al representar las distintas clases que componen el sistema y las relaciones entre ellas.
10.2.
Conceptos generales
Para utilizar correctamente un grafo, es necesario conocer algunas definiciones:
10.2.1.
Conceptos sobre nodos
Nodo: Es cada elemento del grafo. Tambi´en se conoce como v´ertice. En forma conceptual se simboliza:
En los alcances de este documento, un nodo se simboliza as´ı: Grado de entrada: El grado de entrada de un nodo es el n´ umero de enlaces cuyo destino es ese nodo. Grado de salida: El grado de salida de un nodo es el n´ umero de enlaces que parten de ese nodo.
10.2. CONCEPTOS GENERALES
10.2.2.
239
Conceptos sobre enlaces
Enlace: Es la uni´on entre dos nodos del grafo. Si el enlace es unidireccional, hace parte de un grafo dirigido. Si es bidireccional, el grafo es no dirigido. Un enlace tambi´en es llamado arista.
Incidencia: Los enlaces inciden sobre los nodos. Un enlace es incidente en un nodo si el nodo es el origen o destino del enlace.
Enlace c´ıclico: Un enlace es c´ıclico si el origen y destino de ´el, es el mismo nodo. Tambi´en se denominan lazos.
CAP´ITULO 10. GRAFO
240
10.2.3.
Conceptos sobre grafos
Adyacencia: Se dice que hay adyacencia entre dos nodos si est´an unidos por un enlace.
Grafo fuertemente conectado: Un grafo es fuertemente conectado si desde cualquier nodo se puede llegar a todos los dem´as nodos.
Grafo d´ ebilmente conectado: Un grafo es d´ebilmente conectado si no es fuertemente conectado.
Camino simple: Un grafo dirigido tiene un camino simple si es posible recorrer toda la estructura sin repetir ning´ un nodo ni enlace.
Circuito euleriano: Un grafo tiene un circuito euleriano si partiendo de alg´ un nodo, es posible pasar por todos los enlaces del grafo, sin importar si se repiten nodos, pero sin repetir enlaces. Es necesario llegar de nuevo al nodo inicial.
10.2. CONCEPTOS GENERALES
241
Ciclo hamiltoniano: Un grafo tiene un ciclo hamiltoniano si partiendo desde cualquier nodo se pueden recorrer todos los dem´as nodos sin repetir ninguno y finalmente se puede llegar al nodo origen. Mult´ıgrafo: Un grafo es mult´ıgrafo si dos nodos est´an unidos por dos o m´as enlaces.
Grafo simple: Un grafo es simple si no tiene enlaces c´ıclicos y existe un solo enlace entre los nodos.
Grafo no dirigido completo: Un grafo es completo si cada nodo tiene un enlace con todos y cada uno de los nodos restantes del grafo.
242
CAP´ITULO 10. GRAFO
Matriz de adyacencia: Es una representaci´on del grafo, en la cual se puede indicar cu´ando un nodo est´a conectado con otro mediante un valor 0 ´o 1, donde 1 significa un enlace (a, b), ∀(a, b) ∈ graf o.
Matriz de pesos: Es una representaci´on del grafo, en la cual se escriben los pesos para representar cada uno de los enlaces del grafo.
Camino: Un camino es una secuencia de nodos unidos entre s´ı a trav´es de enlaces.
Longitud de un camino: Es el n´ umero de enlaces de un camino. En la imagen corresponde a 3 si el camino es {ab, bc, ca}.
10.3. FORMAS DE RECORRER UN GRAFO
243
Longitud de un camino con pesos: Es la suma de los pesos de los enlaces de un camino. En la imagen corresponde a 3 si el camino es {ab, bc}.
Ciclo: Un ciclo en un grafo es un camino que empieza y termina en el mismo nodo y que tiene al menos un enlace.
Tabla Hash: Es una estructura de datos que se utiliza para almacenar informaci´on en forma de par ordenado ( clave, valor ). La clave es u ´nica para cada elemento y es utilizada para ubicar r´apidamente un elemento en la tabla.
10.3.
Formas de recorrer un grafo
Un recorrido es un procedimiento sistem´atico para explorar un grafo, examinando todos sus nodos y enlaces. Los recorridos m´as eficientes en t´erminos de tiempo son:
CAP´ITULO 10. GRAFO
244
Recorrido en profundidad: Consiste en elegir un nodo inicial y marcarlo como visitado. Luego se elige un enlace y si el enlace conduce a un nodo ya visitado, se devuelve en busca de otro enlace. Si el nodo no est´a visitado, se marca como visitado y se busca un nuevo enlace que se origine en ´el para seguir el recorrido. Recorrido en amplitud (extensi´ on): Este recorrido se hace por niveles. En el primer nivel, se visitan y se marcan como visitados todos los nodos adyacentes al nodo inicial. Luego, en el siguiente nivel, se visitan y se marcan los nodos adyacentes a los nodos del nivel 1 y as´ı sucesivamente.
10.4.
Componentes de un grafo
El grafo que se propone en este documento se compone de los siguientes elementos: Una tabla Hash llamada graph, utilizada para almacenar los nodos del grafo. La clave de cada elemento almacenado en la tabla es el nombre del respectivo nodo, a trav´es del cual se tiene acceso a los nodos del grafo, de forma r´apida y eficiente. Un campo de tipo int llamado size, el cual determina el n´ umero de nodos del grafo. Un campo boolean que permite saber si el grafo ha sido modificado o no despu´es de la u ´ltima vez que se almacen´o en disco. Un campo de tipo Node, utilizado llamado initial. Esta referencia se utiliza para poder determinar el nodo en el cual comienza un recorrido, ya sea por anchura o por profundidad.
10.5.
Operaciones de un grafo
Las operaciones a realizar sobre un grafo se pueden clasificar en operaciones sobre los nodos del grafo y operaciones sobre el grafo.
10.5. OPERACIONES DE UN GRAFO
245
Construcci´ on: Establece un grafo sin nodos. Modificaci´ on: Operaciones que modifican el grafo, ya sea en el n´ umero de nodos del grafo, en el campo de datos de alg´ un nodo o porque se modifica alg´ un enlace. Las operaciones modificadoras se clasifican entre las que operan sobre los nodos del grafo y las que operan sobre el grafo. 1. Operaciones modificadoras sobre los nodos: a) set: Establece o reasigna el campo de datos del nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. b) setWeight: Establece o reasigna el valor del peso del enlace especificado en el nodo especificado. Si el nodo no pertenece al grafo o el n´ umero del puerto no pertenece al vector de puertos del nodo, se lanza una excepci´on. Esta operaci´on est´a asociada con el m´etodo setWeight de Nodos y enlaces. Se consideran dos casos: grafo dirigido y grafo no dirigido. c) setMaxPort: Establece o reasigna el valor del campo maxPort del nodo especificado. Si el nombre del nodo no pertenece al grafo o si se pretende aumentar la restricci´on, se lanza una excepci´on. Se entiende por aumentar la restricci´on cuando se pretende disminuir el valor del campo maxPort (con un valor distinto de cero), o establecer cualquier n´ umero mayor que cero, cuando el valor actual de este atributo es cero. d ) link: Cuando el grafo es dirigido, esta operaci´on permite conectar el nodo origen con el nodo destino en el puerto especificado con un peso especificado. Se lanza una excepci´on si alguno de los nodos no pertenece al grafo o si el n´ umero de puerto no puede ser utilizado, debido a la restricci´on en el campo maxPort. En el caso de los grafos no dirigidos es necesario realizar un enlace en un sentido y otro enlace en sentido contrario para que sea bidireccional. e) unLink: Cuando el grafo es dirigido, simplemente se desconecta el puerto especificado del nodo especificado. En el caso del grafo no dirigido, se deben eliminar los dos enlaces que conforman el enlace bidireccional.
246
CAP´ITULO 10. GRAFO Se lanza una excepci´on si alguno de los nodos no pertenece al grafo o si el n´ umero de puerto no puede ser utilizado, debido a la restricci´on en el campo maxPort. 2. Operaciones modificadoras sobre los grafos: a) newGraph: Elimina todos los elementos del grafo (de la tabla Hash), dej´andolo en su estado inicial. b) add: Adiciona un nodo al grafo. En caso de que el nombre del nodo ya pertenezca al grafo, se lanza una excepci´on. c) remove: Elimina un nodo del grafo. En caso de que el nodo sea el destino de alg´ un enlace o el nodo no pertenezca al grafo, se lanza una excepci´on. d ) setInitial: Permite establecer el nodo inicial del grafo. En caso de que el nodo no pertenezca al grafo, se lanza una excepci´on. An´ alisis: Las operaciones de an´alisis permiten obtener informaci´on del grafo o de alguno de sus nodos. Las operaciones analizadoras se clasifican entre las que operan sobre los nodos del grafo y las que operan sobre el grafo. 1. Operaciones analizadoras sobre los nodos: a) get: Permite obtener la referencia al objeto almacenada en el campo de datos del nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. b) getNumberInputLinks: Retorna el grado de entrada del nodo especificado, es decir, el n´ umero de enlaces que inciden en el nodo. Si el nodo no pertenece al grafo, se lanza una excepci´on. c) getMaxPort: Permite obtener el valor del campo maxPort del nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. d ) getSizeNode: Permite obtener el n´ umero de puertos del nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. e) getOutputLinks: Permite obtener una cadena con los nombres de los nodos a los que les incide un enlace originado en el nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on.
10.5. OPERACIONES DE UN GRAFO
247
f ) getLeastNumberPort: Permite obtener el n´ umero del puerto libre con ´ındice menor en el nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. g) getNode: Permite obtener la referencia al nodo especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. h) getWeight: Permite obtener el valor del peso del nodo especificado en el puerto especificado. Si el puerto no est´a enlazado o el nodo no pertenece al grafo, se lanza una excepci´on. i) getInitial: Permite obtener la referencia al nodo inicial del grafo. j ) isLink: Permite saber si el nodo especificado est´a conectado en el puerto especificado. Si el nodo no pertenece al grafo, se lanza una excepci´on. k ) search: Permite obtener el n´ umero del puerto donde el nodo especificado tiene un enlace con un nodo cuyo contenido es igual al que se recibe por par´ametro. Si el nodo especificado no pertenece al grafo, se lanza una excepcion. l ) whoLink: Permite obtener la referencia al nodo que se encuentra conectado en el puerto especificado. Si el nodo especificado no pertenece al grafo, se lanza una excepci´on. 2. Operaciones analizadoras sobre los grafos: a) getChanged: Permite obtener el valor almacenado en el campo changed. b) getSize: Permite obtener el n´ umero de nodos del grafo. c) getHashTable: Retorna la tabla Hash que almacena el grafo. d ) isInGraph: Permite saber si el nodo especificado pertenece al grafo o no. e) toString: Construye una cadena con el nombre y el campo de datos de todos los nodos que pertenecen al grafo. Persistencia: Las operaciones de persistencia permiten almacenar y recuperar el grafo en un medio persistente (archivo). Las operaciones de persistencia son: 1. save: Permite almacenar el grafo en un archivo. 2. load: Permite recuperar un grafo que se encuentra almacenado en un archivo.
CAP´ITULO 10. GRAFO
248
10.6.
Detalles de las operaciones
10.6.1.
Construcci´ on
El objetivo de esta operaci´on es crear una tabla Hash vac´ıa en la cual ser´an almacenados los nodos del grafo. El campo size inicia en cero (0) y el atributo changed en false. Ver figura 10.1.
Figura 10.1: Construcci´on
10.6.2.
Modificaci´ on
Las operaciones de modificaci´on permiten hacer cambios en el grafo, ya sea porque se actualice el campo de datos de alg´ un nodo, porque se aumente o disminuya el n´ umero de nodos del grafo o porque se modifique alg´ un enlace entre nodos. Operaciones modificadoras sobre los nodos set Permite asignar o reemplazar el campo de datos del nodo especificado en el par´ametro. Recibe adem´as la nueva referencia al objeto que ser´a almacenada en el campo de datos. Si el nombre del nodo no pertenece al grafo, se lanza una excepci´on. Suponga la precondici´on de la figura 10.2 y que desea asignar al campo de datos del nodo "d" un objeto de tipo Integer con el n´ umero 10.
10.6. DETALLES DE LAS OPERACIONES
249
Figura 10.2: set - Precondici´on La poscondici´on se puede apreciar en la figura 10.3.
Figura 10.3: set - Poscondici´on Al finalizar la operaci´on set, se pone en true al atributo changed. setWeight Permite asignar o reemplazar el valor del peso del enlace asociado a uno de los puertos del nodo. Recibe tres par´ametros: 1. el nombre del nodo
CAP´ITULO 10. GRAFO
250 2. el n´ umero del puerto 3. el nuevo valor del peso del enlace
Si el nodo no pertenece al grafo, o el puerto especificado no est´a en uso o no pertenece al vector de puertos, se lanza una excepci´on. Se consideran dos casos, grafo dirigido y grafo no dirigido. En ambos casos, la operaci´on se realiza a trav´es del m´etodo setWeight del nodo especificado, y en ambos casos al finalizar se pone en true al atributo changed. 1. Caso 1: Grafo dirigido Considere la precondici´on de la figura 10.4 y suponga que se desea asignar al enlace del puerto 4 del nodo "e" un valor de 2.5.
Figura 10.4: setWeight - Grafo dirigido - Precondici´on La poscondici´on correspondiente se puede apreciar en la figura 10.5.
10.6. DETALLES DE LAS OPERACIONES
251
Figura 10.5: setWeight - Grafo dirigido - Poscondici´on
2. Caso 2: Grafo no dirigido Aunque en este documento se han utilizado diagramas resumidos, es importante tener en cuenta que los puertos son objetos que almacenan informaci´on importante, especialmente cuando se trata de grafos no dirigidos. Por esta raz´on, en algunas operaciones se hace necesario realizar diagramas m´as detallados para poder explicar apropiadamente los conceptos. Considere la precondici´on de la figura 10.6 y suponga que se desea asignar al enlace del puerto 0 del nodo "c" un valor de 3.4.
Figura 10.6: setWeight - Grafo no dirigido - Precondici´on
CAP´ITULO 10. GRAFO
252
La poscondici´on correspondiente se puede apreciar en la figura 10.7.
Figura 10.7: setWeight - Grafo no dirigido - Poscondici´on Es importante recordar que en el caso del grafo no dirigido lo que ocurre es que el enlace es bidireccional y en realidad se cambia el peso de los dos enlaces, el que va y el que regresa. setMaxPort Permite asignar o reemplazar el n´ umero m´aximo de puertos permitido para el nodo especificado. Recibe adem´as el nuevo valor para el campo maxPort. Si el nodo no pertenece al grafo, se lanza una excepci´on. Esta operaci´on se realiza a trav´es del m´etodo setMaxPort en el nodo especificado. Tambi´en lanza una excepci´on si el valor que se intenta asignar no se puede utilizar por querer aumentar la restricci´on (establecer un n´ umero m´as peque˜ no que el actual, diferente de 0). Suponga la precondici´on de la figura 10.8 y que se desea asignar al nodo "a" un m´aximo de 5 puertos.
10.6. DETALLES DE LAS OPERACIONES
253
Figura 10.8: setMaxPort - Precondici´on
La poscondici´on se puede apreciar en la figura 10.9.
Figura 10.9: setMaxPort - Poscondici´on
Al finalizar la operaci´on setMaxPort, se pone en true al atributo changed. link Permite establecer una conexi´on entre dos nodos. Puede especificarse el peso del enlace o utilizar el valor por omisi´on (1.0). De igual manera
CAP´ITULO 10. GRAFO
254
puede especificarse el n´ umero del puerto o establecer el menor puerto libre por omisi´on. Se consideran dos casos, grafo dirigido y grafo no dirigido. En ambos casos, la operaci´on se realiza a trav´es del m´etodo link del nodo especificado, y en ambos casos al finalizar se pone en true al atributo changed. 1. Caso 1: Grafo dirigido Recibe por par´ametro: • • • •
Nombre del nodo origen Nombre del nodo destino N´ umero de puerto en el nodo origen Peso del enlace
En caso de que alguno de los nodos no pertenezca al grafo se lanza una excepci´on, lo mismo que si se intenta utilizar un n´ umero de puerto negativo o restringido por el atributo maxPort en el nodo origen. Suponga la precondici´on de la figura 10.10 y que desea conectar el nodo "a" con el nodo "d" en el puerto 4 con un peso de 1.2.
Figura 10.10: link - Grafo dirigido - Precondici´on La poscondici´on correspondiente se puede ver en la figura 10.11.
10.6. DETALLES DE LAS OPERACIONES
255
Figura 10.11: link - Grafo dirigido - Poscondici´on 2. Caso 2: Grafo no dirigido En el caso del grafo no dirigido, es necesario asegurarse de que cada enlace sea bidireccional, lo que significa que en lugar de ser no dirigido, es doblemente dirigido. Recibe por par´ametro: • • • • •
Nombre del nodo origen Nombre del nodo destino N´ umero de puerto en el nodo origen N´ umero de puerto en el nodo destino Peso del enlace
En caso de que alguno de los nodos no pertenezca al grafo, se lanza una excepci´on, lo mismo que si se intenta usar un n´ umero de puerto negativo o que no sea permitido por el atributo maxPort. En la operaci´on link para grafos no dirigidos se utiliza el tercer campo del puerto, para que cada nodo pueda saber c´omo se ha realizado cada enlace en la direcci´on inversa. Suponga la precondici´on de la figura 10.12 y que desea conectar el nodo "b" en el puerto 0 con el nodo "c" en el puerto 1 con un peso de 0.3.
CAP´ITULO 10. GRAFO
256
Figura 10.12: link - Grafo no dirigido - Precondici´on La poscondici´on correspondiente se puede ver en la figura 10.13.
Figura 10.13: link - Grafo no dirigido - Poscondici´on
unLink Permite eliminar una conexi´on entre dos nodos. Debe especificarse el nombre del nodo y el n´ umero del puerto. Si el nodo no pertenece al grafo o si el n´ umero del puerto no est´a conectado se genera una excepci´on. Se consideran dos casos, grafo dirigido y grafo no dirigido. En ambos casos, la operaci´on se realiza a trav´es del m´etodo unLink del nodo especificado, y en ambos casos al finalizar se pone en true al atributo changed.
10.6. DETALLES DE LAS OPERACIONES
257
1. Caso 1: Grafo dirigido Suponga la precondici´on de la figura 10.14 y que desea desconectar el nodo "b" en el puerto 1.
Figura 10.14: unLink - Grafo dirigido - Precondici´on La poscondici´on correspondiente se puede ver en la figura 10.15.
Figura 10.15: unLink - Grafo dirigido - Poscondici´on Observe que el n´ umero de conexiones externas en el nodo "a" disminuye en una unidad.
258
CAP´ITULO 10. GRAFO 2. Caso 2: Grafo no dirigido Para poder realizar esta operaci´on, primero es necesario ir al nodo destino para desconectar el puerto en la conexi´on de regreso. El n´ umero del puerto se encuentra almacenado en el campo backPort del puerto (tercer campo). Despu´es se desconecta el puerto especificado en el nodo origen de la conexi´on. Suponga la precondici´on de la figura 10.16 y que desea desconectar el nodo "c" en el puerto 1.
Figura 10.16: unLink - Grafo no dirigido - Precondici´on La poscondici´on correspondiente se puede ver en la figura 10.17.
Figura 10.17: unLink - Grafo no dirigido - Poscondici´on
10.6. DETALLES DE LAS OPERACIONES
259
Operaciones modificadoras sobre el grafo newGraph Esta operaci´on elimina todos los nodos del grafo dej´andolo vac´ıo. La u ´nica diferencia con el estado inicial del grafo es que esta operaci´on deja en true al atributo changed. Suponga la precondici´on de la figura 10.18 y que se desea inicializar nuevamente el grafo.
Figura 10.18: newGraph - Precondici´on La poscondici´on se puede apreciar en la figura 10.19.
Figura 10.19: newGraph - Poscondici´on
add Recibe el nombre del nodo y la referencia al objeto que ser´a almacenada en el campo de datos del nuevo nodo. El objetivo es crear un nodo y si el nombre que se ha pasado por par´ametro no existe en el grafo, se adiciona al grafo. Si no se puede crear el nodo o el nombre ya pertenece al grafo, se lanza una excepci´on.
260
CAP´ITULO 10. GRAFO Suponga que se desea adicionar un nodo al grafo y que se recibe por par´ametro la cadena "nuevo" y una referencia a un objeto de tipo Integer con el n´ umero 10, al grafo de la figura 10.20.
Figura 10.20: add - Precondici´on
Al adicionar el nuevo nodo, el grafo resultante se puede ver en la figura 10.21.
Figura 10.21: add - Poscondici´on
Al finalizar la operaci´on add, se pone en true al atributo changed. Observe que cada nodo est´a referenciado por una entrada en la tabla Hash, lo que permite tener nodos “sin ninguna conexi´on externa”(con respecto s´olo a los nodos del grafo). Las entradas en la tabla se dibujan de manera consecutiva a pesar de que se trata de una tabla de dispersi´on. Debido a esta situaci´on, es posible que el orden en el cual se muestran las diferentes entradas sea
10.6. DETALLES DE LAS OPERACIONES
261
diferente al que se utilice en las tablas en el momento de una implementaci´on. remove Esta operaci´on permite eliminar un nodo del grafo. Si el nodo especificado es destino de alg´ un enlace o si no pertenece al grafo, se lanza una excepci´on. Suponga la precondici´on de la figura 10.22 y que desea eliminar el nodo "c".
Figura 10.22: remove - Precondici´on
Al eliminar el elemento, el grafo se puede ver en la figura 10.23.
Figura 10.23: remove - Poscondici´on Observe que el nodo desapareci´o y que la cantidad de nodos del grafo disminuy´o en una unidad. Adem´as se ha actualizado el n´ umero de conexiones externas a los nodos que ten´ıan enlaces que sal´ıan del nodo eliminado, en este caso en el nodo "b" que pas´o de 2 conexiones externas a 1. Al finalizar se pone en true al atributo changed.
CAP´ITULO 10. GRAFO
262 setInitial
Esta operaci´on permite asignar el nodo inicial del grafo. Si el nodo especificado no pertenece al grafo, se lanza una excepci´on.
10.6.3.
An´ alisis
Las operaciones de an´alisis permiten obtener informaci´on del grafo o de alg´ un nodo que pertenezca a ´el. Operaciones analizadoras sobre los nodos get Recibe por par´ametro el nombre del nodo del que se desea obtener la referencia almacenada en el campo de datos. Si el nodo no pertenece al grafo, se lanza una excepci´on. En el caso de la figura 10.24, si se le pasa por par´ametro el nombre "b" a la operaci´on get, se retorna una referencia al objeto de tipo Integer que almacena un 2.
Figura 10.24: get
10.6. DETALLES DE LAS OPERACIONES
263
getNumberInputLinks Esta operaci´on permite obtener el n´ umero enlaces cuyo destino es el nodo especificado. Si el nodo especificado no pertenece al grafo se lanza una excepci´on. Suponga el grafo de la figura 10.25. Si se le pasa por par´ametro el nombre "a", a la operaci´on getNumberInputLinks, retorna 1, o si se le pasa "b", retorna 3.
Figura 10.25: getNumberInputLinks
getMaxPort Esta operaci´on permite obtener el n´ umero m´aximo de puertos permitido para el nodo especificado (el campo maxPort). Si el nodo especificado no pertenece al grafo se lanza una excepci´on. Suponga el grafo de la figura 10.26. Si se le pasa por par´ametro el nombre "a" a la operaci´on getMaxPort, retorna 4, o si se le pasa el nodo "b", retorna 0.
CAP´ITULO 10. GRAFO
264
Figura 10.26: getMaxPort
getOutputLinks Esta operaci´on retorna los nombres y su contenido, de los nodos directamente conectados con el nodo especificado, es decir, los nodos que son el destino de alg´ un enlace que se origina en el nodo. Si el nodo no pertenece al grafo, se lanza una excepci´on. Ver figura 10.27.
Figura 10.27: getOutputLinks De acuerdo con la figura 10.27, si se le pasa por par´ametro el nombre "a" a la operaci´on getOutputLinks, retorna, en forma de cadena: 0: b { 2 } - [ 1.0 ] 1: null
10.6. DETALLES DE LAS OPERACIONES
265
2: null 3: c { 4 } - [ 1.0 ] Al interpretar esta cadena se deduce f´acilmente que el nodo "a" est´a conectado en el puerto 0 con el nodo "b" cuyo contenido es 2) y con un peso de 1.0; tiene null en los puertos 1 y 2, y que est´a conectado con el nodo "c" en el puerto 3, con contenido 4 y un peso en el enlace de 1.0. getNode Esta operaci´on permite obtener la referencia al nodo especificado. Si el nodo no pertenece al grafo se lanza una excepci´on. Es responsabilidad de l usuario la correcta utilizaci´on del nodo obtenido. Por ejemplo, no puede modificarse el nombre del nodo, porque el grafo pierde informaci´on y puede ocasionar inconsistencias. getLeastNumberPort Esta operaci´on permite obtener el n´ umero del puerto libre con ´ındice menor en el nodo especificado. Si el nodo especificado no pertenece al grafo se lanza una excepci´on. En el caso de la figura 10.28, si se le pasa por par´ametro el nombre "a" a la operaci´on getLeastNumberPort, retorna 3, o si se le pasa "e", retorna 0.
Figura 10.28: getLeastNumberPort
CAP´ITULO 10. GRAFO
266 getSizeNode
Esta operaci´on permite obtener el n´ umero de puertos del nodo especificado. Si el nodo no pertenece al grafo se lanza una excepci´on. Suponga el grafo de la figura 10.29. Si se le pasa por par´ametro el nombre "a" a la operaci´on getSizeNode, retorna 3, o si se le pasa "c", retorna 4.
Figura 10.29: getSizeNode
getWeight Esta operaci´on permite obtener el peso del enlace especificado en el nodo especificado. Si el nodo no pertenece al grafo o el puerto no est´a enlazado, se lanza una excepci´on. Suponga el grafo de la figura 10.30. Si se le pasa por par´ametro el nombre "c" y el n´ umero de puerto 3 a la operaci´on getWeight, retorna 3.2.
10.6. DETALLES DE LAS OPERACIONES
267
Figura 10.30: getWeight
getInitial Esta operaci´on permite obtener la referencia al nodo inicial del grafo. isLink Esta operaci´on permite saber si el enlace especificado en el nodo especificado est´a conectado con otro nodo o no. Si el nodo no pertenece al grafo, se lanza una excepci´on. Suponga el grafo de la figura 10.31. Si se le pasa por par´ametro el nombre "c" y el n´ umero de puerto 3, la operaci´on isLink retorna true. De igual manera, el nodo "b" en el puerto 0 es false.
CAP´ITULO 10. GRAFO
268
Figura 10.31: isLink
search Esta operaci´on permite saber cu´al de los puertos del nodo especificado se tiene conectado a un nodo cuyo campo de datos es igual al que se recibe por par´ametro. Encuentra la primera ocurrencia, si no hay coincidencia en ninguno de los nodos vecinos, retorna -1. Suponga el grafo de la figura 10.32. Si se le pasa por par´ametro el nombre "a" y una referencia a un objeto Integer con un valor de 4, retorna el n´ umero de puerto 1. De igual manera, si pasa por par´ametro el nodo "b" y la referencia al Integer 10, retorna -1. Es de anotar que no se trata de buscar el mismo objeto sino un objeto con igual contenido al que se pasa por par´ametro.
10.6. DETALLES DE LAS OPERACIONES
269
Figura 10.32: search
whoLink Recibe por par´ametro un nodo y un n´ umero de puerto. Esta operaci´on permite obtener la referencia al nodo conectado en el puerto especificado. Si el nodo no est´a conectado, retorna null. Si el nodo especificado en el par´ametro no pertenece al grafo o el puerto no pertenece al vector de puertos del nodo, se lanza una excepci´on. Suponga el grafo de la figura 10.33. Si se le pasa por par´ametro el nombre "a" y el puerto 1, retorna una referencia al nodo "c", si se pasa por par´ametro el nodo "e" y el puerto 4, retorna una referencia al nodo "c". De igual manera, si se pasa por par´ametro el nodo "b" y el puerto 3 retorna la referencia null.
CAP´ITULO 10. GRAFO
270
Figura 10.33: whoLink
Operaciones analizadoras sobre el grafo getSize Esta operaci´on permite obtener el n´ umero de nodos del grafo. En el caso del grafo de la figura 10.34, retorna 5.
Figura 10.34: getSize
10.6. DETALLES DE LAS OPERACIONES
271
isInGraph Esta operaci´on permite saber si el nombre que se pasa por par´ametro pertenece a uno nodo del grafo o no. Retorna un valor boolean (true o false). Suponga el grafo de la figura 10.35. Si se le pasa por par´ametro el nombre "c" retorna true, pero si se pasa "f" retorna false.
Figura 10.35: isInGraph
getChanged No recibe ning´ un par´ametro. Retorna el valor del campo changed. getHashtable No recibe ning´ un par´ametro. Retorna la tabla Hash que almacena los diferentes nodos del grafo, para ser utilizada en aplicaciones que la requieran. toString Esta operaci´on construye una cadena con la informaci´on del grafo. La cadena se conforma con el nombre de cada nodo, el dato que almacena (el objeto) y las conexiones que se originan en el nodo. Ver figura 10.36.
CAP´ITULO 10. GRAFO
272
Figura 10.36: toString Tomando la situaci´on de la figura 10.36, la operaci´on toString retorna la cadena: Nodo: a { 1 } 0: b { 2 } [ 1.0 ] 1: null 2: null 3: c { 4 } [ 1.0 ] Nodo: b { 2 } 0: null 1: c { 4 } [ 1.0 ] Nodo: c { 4 } 0: null 1: null 2: a { 1 } [ 1.0 ]
10.6.4.
Recorridos
Los recorridos son operaciones que permiten visitar todos los nodos de manera que no se repita ninguno. Al realizar un recorrido del grafo se obtiene una lista sencillamente enlazada con los nombres de los nodos en el orden que le corresponda, de acuerdo con el recorrido elegido. El recorrido inicia en el nodo que ha sido determinado como nodo inicial.
10.6. DETALLES DE LAS OPERACIONES
273
depth Este recorrido, conocido como recorrido en profundidad funciona de la siguiente manera: primero se procesa el nodo inicial y a continuacin se hace el recorrido en profundidad de cada uno de sus vecinos en orden ascendente, iniciando desde el vecino con 織覺ndice cero. Procesar el nodo significa obtener el nombre, adicionarlo al final de la lista y marcarlo como visitado utilizando el atributo flag. El resultado del recorrido en profundidad del grafo de la figura 10.37 es: A B E F G C D.
Figura 10.37: Recorridos
width Este recorrido, conocido como recorrido en anchura permite obtener una lista sencillamente enlazada cuyo contenido corresponde a los nombres de los nodos en el recorrido por anchura. Este recorrido funciona de la siguiente manera: primero se procesa el nodo inicial y a continuacin se procesan sus vecinos directos, iniciando desde el vecino con 織覺ndice cero. Luego, se procesan los vecinos directos de cada uno de los vecinos directos del nodo inicial, sin repetir ninguno. Procesar el nodo significa obtener el nombre, adicionarlo al final de la lista y marcarlo como visitado utilizando el atributo flag. El resultado del recorrido en anchura del grafo de la figura 10.37 es: A B C D E F G.
CAP´ITULO 10. GRAFO
274
10.6.5.
Persistencia
Las operaciones de persistencia permiten almacenar y recuperar el grafo completo desde o hacia un archivo. La serializaci´on de objetos en Java permite realizar esta tarea de forma casi autom´atica. La serializaci´on de objetos de Java es el proceso de escribir el estado de un objeto en un flujo de bytes (incluyendo los objetos que se est´en referenciando). Las operaciones de persistencia para los grafos son: save: Almacena en un archivo el contenido del grafo. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Puede disparar una excepci´on si el archivo no puede ser creado o no se puede escribir en ´el. Al finalizar la operaci´on save se pone en false el valor del atributo changed. load: Carga a la memoria el grafo completo. Recibe por par´ametro el nombre del archivo. No retorna ning´ un valor. Si no existe el archivo o no se puede leer, se dispara una excepci´on. Ver figura 10.38
Figura 10.38: Persistencia
Parte IV C´ odigo Fuente
275
11
Instalaci´on del paquete El paquete realmente no se necesita instalar. Simplemente se debe almacenar en alguna carpeta del disco duro y ense˜ narle al editor que busque el paquete en esa carpeta. A continuaci´on, se pueden apreciar los pasos que permiten utilizar el paquete EstrDatos. 1. Debe crear una carpeta con el nombre que desee. En este caso, la carpeta se llama EstrDatos. Por ejemplo, esta carpeta puede estar ubicada en la ruta: D:\Archivos de programa\j2sdk1.4.1_02.
En esa carpeta debe guardar el archivo EstrDatos.jar, el cual contiene el paquete EstrDatos.
278
´ DEL PAQUETE CAP´ITULO 11. INSTALACION
2. Es necesario configurar el editor para que pueda encontrar las clases que pertenecen al paquete. Por ejemplo el programa JCreator LE de Xinox Software, disponible en http://www.jcreator.com.
3. En el caso de JCreator, seleccione Options del men´ u Configure.
4. En el cuadro de di´alogo Options seleccione la opci´on JDK Profiles. En la lista de perfiles, aparece resaltado el perfil por omisi´on. En este caso, es el u ´nico que tenemos disponible. Haga clic en el bot´on Edit.
279
5. En el cuadro de di´alogo JDK Profile haga clic en Add y luego en Add Archive.
6. Finalmente, en el cuadro de di´alogo Abrir, seleccione EstrDatos, la carpeta que cre´o en el paso 1. Esta carpeta se debe abrir y en ella encontrar´a el archivo EstrDatos.jar. Selecci´onelo y haga clic sobre el bot´on Abrir. Luego haga clic dos veces sobre el bot´on OK.
Nota: En Windows XP, los pasos son los mismos, solo que depende del tipo de usuario y los permisos que tenga cada usuario.
280
´ DEL PAQUETE CAP´ITULO 11. INSTALACION
12 Ejemplos
Para poder utilizar el paquete EstrDatos es necesario que el editor que utilice para crear los programas en Java tenga conocimiento de la ubicaci´on del archivo EstrDatos.jar. Este procedimiento se puede apreciar en la p´agina 277. A continuaci´on se puede apreciar un ejemplo sencillo de la utilizaci´on de la clase Node.java.
Node01.java import EstrDatos.*; import javax.swing.*; public class Nodo01 { public static void main ( String args[ ] ) { Node a, b, c; Integer temporal; JTextArea areaSalida;
CAP´ITULO 12. EJEMPLOS
282 areaSalida = new JTextArea
( 10, 5 );
try { a = new Node ( ); b = new Node ( ); c = new Node ( ); a.set ( new Integer ( 7 ) ); b.set ( new Integer ( 5 ) ); a.link ( b, 0 ); a.link ( b, 4 ); a.link ( c, 1 ); b.link ( a, 0 ); c.link ( b, 1 ); if ( a.isLink ( 0 ) ) { a.unLink ( 0 ); } if ( a.isData ( ) == true ) { temporal = ( Integer ) a.get ( ); c.set ( temporal ); } areaSalida.append ( a.toString ( ) ); areaSalida.append ( "\n" ); areaSalida.append ( b.toString ( ) ); areaSalida.append ( "\n" ); areaSalida.append ( c.toString ( ) ); areaSalida.append ( "\n" ); JOptionPane.showMessageDialog ( null, areaSalida, "Ejemplo de Nodos", JOptionPane.INFORMATION_MESSAGE ); }
283 catch ( Exception exc) { JOptionPane.showMessageDialog ( null, exc.getMessage ( ), "Error", JOptionPane.ERROR_MESSAGE ); } } }
La salida del ejemplo anterior se puede ver en la figura 12.
Ejemplos como el anterior puede encontrar en el CD que acompaË&#x153; na este documento, en la carpeta Ejemplos. Esta carpeta tiene subcarpetas en las cuales puede encontrar ejemplos de las diferentes clases que componen el paquete EstrDatos.
284
CAP´ITULO 12. EJEMPLOS
13
C´odigo Fuente El c´odigo fuente del paquete EstrDatos est´a compuesto por 15 clases: 1. Node.java 2. Link.java 3. List.java 4. SingleList.java 5. CircularSingleList.java 6. DoubleList.java 7. CircularDoubleList.java 8. Queue.java 9. Stack.java 10. Tree.java 11. BinaryTree.java
286
´ CAP´ITULO 13. CODIGO FUENTE
12. Graph.java 13. DirectedGraph.java 14. UnDirectedGraph.java 15. EstrDatosException.java Los identificadores est´an en ingl´es con el fin de familiarizar al estudiante con los nombres de los m´etodos que se encuentran en otras APIs escritas en Java. Se utiliz´o en estandar que siguen muchas personas en la comunidad de desarrollo de Java para la asignaci´on de nombres a las clases, m´etodos y atributos. Los identificadores que se usan para las clases comienzan con una letra may´ uscula. El resto de letras debe ir en min´ uscula. Si el nombre de la clase tiene m´as de una palabra, no se usan espacios en blanco ni otro tipo de separadores, pero la primera letra de cada palabra debe ir en may´ uscula. Por ejemplo: CircularDoubleList. En el caso de las variables internas, atributos de clase y nombres de m´etodos, siguen el mismo est´andar de las clases pero no inician con letra may´ uscula. En todos los casos, se omiti´o el uso de abreviaturas con el fin de aumentar la claridad en el c´odigo.
13.1. MODELOS
13.1.
287
Modelos
En la figura 13.1 se puede apreciar el diagrama de las clases que componen el paquete EstrDatos.
Figura 13.1: Diagrama de clases En la figura 13.2 se puede apreciar el diagrama de paquetes con una arquitectura sencilla para una aplicaci´on que utilice el paquete EstrDatos.
Figura 13.2: Arquitectura de una aplicaci´on
´ CAP´ITULO 13. CODIGO FUENTE
288
En la figura 13.3 se puede apreciar el diagrama de paquetes con una arquitectura un poco m´as detallada para una aplicaci´on que utilice el paquete EstrDatos.
Figura 13.3: Arquitectura de una aplicaci´on A continuaci´on se puede apreciar el c´odigo fuente de la clase Node.java.
Node.java package EstrDatos; import java.io.*; import java.util.Vector; /** * Ultima actualizacion: noviembre 1 de 2004 * * Libreria de clase para la gestion de estructuras de datos basada en * nodos y enlaces. * * @author Carlos Eduardo Gomez Montoya. <p> * * Asesoria y colaboracion: Julian Esteban Gutierrez Posada * Universidad del Quindio. */
13.1. MODELOS
289
public class Node implements Serializable { private Object data; private String name; private int numberInputLinks; private int maxPort; private Vector port; private boolean flag; /* //
------------------------------------------------------------------ */ --------------------- METODOS CONSTRUCTORES ----------------------
/* // /*
------------------------------------------------------------------ */ ------------------------ Sin parametros ------------------------------------------------------------------------------------------- */
/** * <br> * * * @param */
Este metodo crea el nodo sin restricciones y con el nombre por omision. Ninguno.
public Node ( ) throws EstrDatosException { this ( 0, "noName" ); } /* // /*
------------------------------------------------------------------ */ ------------------- Recibe el nombre del nodo ------------------------------------------------------------------------------------- */
/** * <br> * * * @param */
Este metodo crea el nodo sin restricciones, con el nombre especificado newName El nuevo nombre del nodo.
public Node ( String newName ) throws EstrDatosException { this ( 0, newName ); }
´ CAP´ITULO 13. CODIGO FUENTE
290 /* // /*
------------------------------------------------------------------ */ ------------------ Recibe el maximo de puertos ------------------------------------------------------------------------------------ */
/** * <br> * * * @param */
Este metodo crea el nodo con el maximo numero de puertos recibido por parametro max El maximo de puertos.
public Node ( int max ) throws EstrDatosException { this ( max, "noName" ); } /* // /*
------------------------------------------------------------------ */ ------------ Recibe el maximo de puertos y el nombre ------------------------------------------------------------------------------ */
/** * <br> * * <br> * * <br> * * <br> * * * * @param * @param */
Este metodo crea el nodo con un vector de puertos para los posibles enlaces del nodo, con un puerto, contenido null. Recibe por parametro el numero maximo de puertos para el nodo y el nombre del nodo. Lanza una excepcion si no hay memoria para el vector de puertos (de un solo nodo) Establece el nombre del nodo y el numero maximo de puertos de acuerdo a los valores recibidos por parametro. Inicia el numero de conexiones al nodo en cero. max El numero maximo de puertos permitido newName El nuevo nombre del nodo
public Node ( int max, String newName ) throws EstrDatosException { port = new Vector ( 1 ); // capacidad 1, sin contenido if ( port == null ) { throw new EstrDatosException ( "ERROR, no hay memoria crear los puertos." ); }
13.1. MODELOS
291
if ( max < 0 ) { throw new EstrDatosException ( "ERROR, maximo numero de puertos no valido."); } port.setSize ( 1 maxPort name numberInputLinks flag
); = max; = newName; = 0; = false;
} /* //
------------------------------------------------------------------ */ --------------------- METODOS MODIFICADORES ----------------------
/* // /*
------------------------------------------------------------------ */ -------------------- Asigna el campo de datos ------------------------------------------------------------------------------------- */
/** * <br> * * * @param * @return */
Este metodo asigna o reemplaza el valor al campo data de acuerdo con el parametro newData El nuevo valor del campo data No retorna ningun valor
public void set ( Object newData ) { data = newData; } /* // /*
------------------------------------------------------------------ */ ------------------- Diminuye numberInputLinks ------------------------------------------------------------------------------------- */
/** * <br> * * * @param * @return */
Este metodo disminuye en una unidad el numero de conexiones entrantes del nodo Ninguno No retorna ningun valor
´ CAP´ITULO 13. CODIGO FUENTE
292 protected void less ( ) { numberInputLinks--; } /* // /*
------------------------------------------------------------------ */ ------------------- Aumenta numberInputLinks -------------------------------------------------------------------------------------- */
/** * <br> * * * @param * @return */
Este metodo aumenta en una unidad el numero de conexiones entrantes del nodo Ninguno No retorna ningun valor
protected void plus ( ) { numberInputLinks++; } /* // /*
------------------------------------------------------------------ */ --------------------- Establece el nombre ----------------------------------------------------------------------------------------- */
/** * <br> * * * @param * @return */
Este metodo asigna el valor al campo name de acuerdo con el parametro newName El nuevo valor del campo name No retorna ningun valor
public void setName ( String newName ) { name = newName; } /* // /*
------------------------------------------------------------------ */ ---------------------- Establece maxPort ------------------------------------------------------------------------------------------ */
13.1. MODELOS /** * <br> * * * @param * @return */
293
Este metodo asigna el valor al campo maxPort de acuerdo con el parametro max El nuevo valor del campo maxPort No retorna ningun valor
public void setMaxPort ( int max ) throws EstrDatosException { if ( max == 0 ) { maxPort = max; } else { if ( maxPort != 0 && max > maxPort ) { maxPort = max; } else { throw new EstrDatosException ( "ERROR, maximo numero de puertos no valido." ); } } } /* // /*
------------------------------------------------------------------ */ ---------------------- Establece el peso ------------------------------------------------------------------------------------------ */
/** * <br> * * @param * @param * @return */
Este metodo reemplaza el peso de un puerto. numberPort El numero del puerto weight El peso double
´ CAP´ITULO 13. CODIGO FUENTE
294
public void setWeight ( int numberPort, double weight ) throws EstrDatosException { Link temporal; if (
numberPort >= 0 && numberPort < port.size ( ) && isLink ( numberPort ) == true )
{ temporal = ( Link ) port . get ( numberPort ); temporal.setWeight ( weight ); } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } /* // /*
------------------------------------------------------------------ */ ------------- Establece una conexion unidireccional ------------------------------------------------------------------------------- */
/** * <br> * * * <br> * <br> * * * <br> * * * @param * @param * @param * @return */
Este metodo conecta un nodo con otro en el numero de puerto indicado, el numero del puerto inicia en 0 (internamente el indice del vector tambien inicia en 0) Asigna el peso de acuerdo con el parametro Si el numero del puerto es positivo pero no existe en el vector de puertos, crece automaticamente, siempre y cuando no sobrepase el numero maximo de puertos permitido Si el numero de puerto es negativo o sobrepasa el maximo numero de puertos permitido, se lanza una excepcion. nodeLink El nodo con quien se desea conectar numberPort El numero del puerto newWeight El peso para el enlace No retorna ningun valor
13.1. MODELOS
295
public void link ( Node nodeLink, int numberPort, double newWeight ) throws EstrDatosException { Link puerto; puerto = new Link ( nodeLink, newWeight ); // caso 1: El puerto existe. El puerto 0 siempre existe if ( numberPort >= 0 && numberPort < port.size ( ) ) { // Si era null el enlace if ( isLink ( numberPort ) == false ) { port.set ( numberPort, puerto ); whoLink ( numberPort ).plus ( ); } else { // Si se sobreescribe un enlace existente whoLink ( numberPort ).less ( ); port.set ( numberPort, puerto ); whoLink ( numberPort ).plus ( ); } } else { // caso 2: El numero de puerto no existe // caso 2.1: Hay restriccion en el numero de puertos if ( maxPort > 0 ) { // caso 2.1.1: El numero de puerto es valido if ( numberPort > 0 && numberPort < maxPort ) { port.setSize ( numberPort + 1 ); port.set ( numberPort, puerto ); whoLink ( numberPort ).plus ( ); } else { // caso 2.1.2: El numero de puerto no es valido throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } }
´ CAP´ITULO 13. CODIGO FUENTE
296 else {
// caso 2.2: No hay restriccion en el numero de puertos // caso 2.2.1: El numero de puerto es valido if ( numberPort > 0 ) { port.setSize ( numberPort + 1 ); if ( nodeLink != null ) { port.set ( numberPort, puerto ); whoLink ( numberPort ).plus ( ); } } else { // caso 2.2.2: El numero de puerto no es valido throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } } } /* // /*
------------------------------------------------------------------ */ ------------- Establece una conexion unidireccional ------------------------------------------------------------------------------- */
/** * <br> * * * @param * @param * @return */
Este metodo conecta un nodo con otro en el numero de puerto indicado, con peso por omision de -1. nodeLink El nodo con quien se desea conectar numberPort El numero del puerto No retorna ningun valor
public void link ( Node nodeLink, int numberPort ) throws EstrDatosException { link ( nodeLink, numberPort, 1.0 ); } /* // /*
------------------------------------------------------------------ */ ---------------------- Elimina una conexion --------------------------------------------------------------------------------------- */
13.1. MODELOS
/** * <br> * * * <br> * * * @param * @return */
297
Este metodo desconecta el nodo en el puerto indicado, el numero del puerto inicia en 0 (internamente el indice del vector tambien inicia en 0) Si el numero del puerto esta por fuera de los limites del vector de puertos se lanza una excepcion. numberPort El numero del puerto No retorna ningun valor
public void unLink ( int numberPort ) throws EstrDatosException { if ( numberPort >= 0 && numberPort < port.size ( ) ) { if ( isLink ( numberPort ) == true ) { whoLink ( numberPort ).less ( ); port.set ( numberPort, null ); } } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } /* // /*
------------------------------------------------------------------ */ ------------ Establece un valor para el atributo flag ----------------------------------------------------------------------------- */
/** * <br> Este metodo asigna o cambia el valor almacenado en el * atributo flag * * @param valor El nuevo valor para el atributo flag * @return No retorna ningun valor */ public void setFlag ( boolean valor ) { flag = valor; }
´ CAP´ITULO 13. CODIGO FUENTE
298 /* //
------------------------------------------------------------------ */ --------------------- METODOS ANALIZADORES -----------------------
/* // /*
------------------------------------------------------------------ */ ------------------- Obtener el campo de datos ------------------------------------------------------------------------------------- */
/** * <br> * <br> * <br> * * * @param * @return */
Este metodo retorna el valor del atributo data, si existe Si no hay informacion en el nodo, lanza una excepcion; es responsabilidad del usuario verificar primero si hay o no informacion. Ninguno Object
public Object get ( ) throws EstrDatosException { if ( data != null ) { return data; } else { throw new EstrDatosException ( "ERROR, El nodo no tiene datos." ); } } /* // /*
------------------------------------------------------------------ */ ---------------------- Obtener el nombre ----------------------------------------------------------------------------------------- */
/** * <br> Este metodo retorna el valor del atributo name. * * @param Ninguno * @return String */ public String getName ( ) { return name; }
13.1. MODELOS /* // /*
299
------------------------------------------------------------------ */ ------------ Obtener el numero de conexiones externas ----------------------------------------------------------------------------- */
/** * <br> Este metodo retorna el valor del atributo numberInputLinks * * @param Ninguno * @return int */ public int getNumberInputLinks ( ) { return numberInputLinks; } /* // /*
------------------------------------------------------------------ */ ---------- Obtener el numero maximo de puertos permitido -------------------------------------------------------------------------- */
/** * <br> Este metodo retorna el valor del atributo maxPort. * * @param Ninguno * @return int */ public int getMaxPort ( ) { return maxPort; } /* // /*
------------------------------------------------------------------ */ ----------------- Obtener el numero de puertos ------------------------------------------------------------------------------------ */
/** * <br> Este metodo retorna el numero de puertos del nodo. * * @param No recibe ningun valor * @return int */
´ CAP´ITULO 13. CODIGO FUENTE
300 public int getSize ( ) { return port.size ( ); } /* // /*
------------------------------------------------------------------ */ ----------------------- Obtener un puerto ----------------------------------------------------------------------------------------- */
/** * <br> Este metodo retorna puerto especificado * * @param numberPort El numero del puerto * @return Link */ public Link getPort ( int numberPort ) throws EstrDatosException { Link temporal; if ( numberPort >= 0 && numberPort < port.size ( ) ) { temporal = ( Link ) port . get ( numberPort ); return temporal; } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } /* // /*
------------------------------------------------------------------ */ ----------------- Obtener el peso de un puerto ------------------------------------------------------------------------------------ */
/** * <br> Este metodo retorna el peso de un puerto. * * @param numberPort El numero del puerto * @return double */
13.1. MODELOS
301
public double getWeight ( int numberPort ) throws EstrDatosException { Link temporal; if ( isLink ( numberPort ) == true ) { temporal = ( Link ) port . get ( numberPort ); return temporal.getWeight ( ); } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } /* // /*
------------------------------------------------------------------ */ ----------- Obtener el puerto libre con indice menor ------------------------------------------------------------------------------ */
/** * <br> * * * @param * @return */
Este metodo permite obtener el numero de puerto libre con indice menor No recibe ningun valor int
public int getLeastNumberPort ( ) throws EstrDatosException { int i; for ( i = 0; i < getSize ( ); i++ ) { if ( isLink ( i ) == false ) { return i; } } return i; }
´ CAP´ITULO 13. CODIGO FUENTE
302 /* // /*
------------------------------------------------------------------ */ ---- Obtener una cadena con las conexiones salientes del nodo --------------------------------------------------------------------- */
/** * <br> * * * @param * @return */
Este metodo construye una cadena que permite conocer los nodos que estan directamente conectados con el nodo No recibe ningun valor String
public String getOutputLinks ( ) throws EstrDatosException { int i; String cadena; cadena = ""; for ( i = 0; i < getSize ( ); i++) { if ( isLink ( i ) == true ) { cadena += i + ": " + whoLink ( i ).getName ( ) + " { " + whoLink ( i ).toString ( ) + " } - [ " + getWeight ( i ) + " ]\n"; } else { cadena += i + ": " + "null" + "\n"; } } return cadena; } /* // /*
------------------------------------------------------------------ */ -------------- Obtener el valor del atributo flag --------------------------------------------------------------------------------- */
13.1. MODELOS
303
/** * <br> Este metodo retorna el valor del atributo flag. * * @param Ninguno * @return boolean */ public boolean getFlag ( ) { return flag; } /* // /*
------------------------------------------------------------------ */ ----------------- El campo de datos es valido? ------------------------------------------------------------------------------------ */
/** * <br> * <br> * * @param * @return */
Este metodo retorna un valor false si el campo data es null En caso contrario, retorna true. Ninguno boolean
public boolean isData ( ) { if ( data != null ) { return true; } else { return false; } } /* // /*
------------------------------------------------------------------ */ ------------------ El puerto esta conectado? -------------------------------------------------------------------------------------- */
´ CAP´ITULO 13. CODIGO FUENTE
304 /** * <br> * * * * @param * @return */
Este metodo permite saber si un puerto del nodo esta enlazado o no con otro nodo, el numero del puerto inicia en 0 (igual que el indice interno del vector) numberPort El numero del puerto boolean
public boolean isLink ( int numberPort ) throws EstrDatosException { if ( maxPort == 0 ) { if ( numberPort >= 0 ) { if ( numberPort < port.size ( ) && port.get ( numberPort ) != null ) { return true; } else { return false; } } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } else { if ( numberPort >= 0 && numberPort < maxPort ) { if ( numberPort < port.size ( ) && port.get ( numberPort ) != null ) { return true; } else { return false; } }
13.1. MODELOS
305
else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } } /* // /*
------------------------------------------------------------------ */ -------------- Buscar un vecino con un objeto dado -------------------------------------------------------------------------------- */
/** * <br> * * * <br> * * @param * @return */
Este metodo permite conocer el numero de puerto utilizado para la conexion con un nodo cuyo campo de datos se recibe por parametro Si no se encuentra retorna -1. element El elemento a buscar int
public int search ( Object element ) throws EstrDatosException { int i; Object temporal; for ( i = 0; i < getSize ( ); i++ ) { if ( isLink ( i ) == true ) { temporal = whoLink ( i ) . get ( ); if ( temporal . equals ( element ) == true ) { return i; } } } return -1; } /* // /*
------------------------------------------------------------------ */ -------------- Con quien esta conectado el puerto --------------------------------------------------------------------------------- */
´ CAP´ITULO 13. CODIGO FUENTE
306 /** * <br> * * * <br> * * * @param * @return */
Este metodo permite conocer con quien esta enlazado el nodo en un puerto especificado, el numero del puerto inicia en 0 (internamente el indice del vector tambien inicia en 0) Si el numero del puerto esta por fuera de los limites del vector de puertos se lanza una excepcion. numberPort El numero del puerto Node
public Node whoLink ( int numberPort ) throws EstrDatosException { Link temporal; if ( maxPort == 0 ) { if ( numberPort >= 0 ) { if ( isLink ( numberPort ) == true ) { // usa el molde porque retorna un object temporal = ( Link ) port.get ( numberPort ); return ( Node ) temporal.getTarget ( ); } else { return null; } } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } else { if ( numberPort >= 0 && numberPort < maxPort ) { if ( isLink ( numberPort ) == true ) { // usa el molde porque retorna un object temporal = ( Link ) port.get ( numberPort ); return ( Node ) temporal.getTarget ( ); }
13.2. COMPILAR LAS LIBRER´IAS
307
else { return null; } } else { throw new EstrDatosException ( "ERROR, numero de puerto no valido." ); } } } /* // /*
------------------------------------------------------------------ */ ------------------------ Como imprimir? ------------------------------------------------------------------------------------------- */
/** * <br> * * <br> * <br> * * * @param * @return */
Este metodo construye una cadena con el contenido del campo data en forma de cadena En este caso, se puede ver el nombre del nodo y los datos Si no esta definido el campo de datos, se obtiene unicamente el nombre. No recibe ningun valor String
public String toString ( ) { return data + ""; } /* ------------------------------------------------------------------ */ } // fin de la clase Node
El c´odigo fuente de las dem´as clases que componen el paquete lo puede encontrar en el CD que acompa˜ na este documento, en la carpeta Codigo Fuente, en la subcarpeta Librerias.
13.2.
Compilar las librer´ıas
Un archivo .jar es un archivo comprimido que permite agrupar un conjunto de clases y los recursos asociados. En el caso de las librer´ıas que componen el
´ CAP´ITULO 13. CODIGO FUENTE
308
paquete EstrDatos, son 15 clases y no tienen ning´ un otro recurso asociado. Si desea modificar alguna de las clases y compilarla de nuevo, es necesario tener en cuenta las siguientes instrucciones. Aseg´ urese de que la m´aquina virtual de Java (JVM) est´a asociada correctamente y en la ruta correcta. Compile los archivos.java correspondientes, indicando donde se encuentra el c´odigo fuente que desea compilar. Construir el archivo .jar en el cual se va a comprimir los archivos .class con el c´odigo binario de las librer´ıas. Si lo prefiere, puede crear un archivo .bat que facilite este proceso, con las siguientes instrucciones: path "D:\Archivos de programa"\"j2sdk1.4.1_02"\bin;c:\windows javac -g:none -d . SrcEstrDatos\*.java jar cvf EstrDatos.jar EstrDatos\
Naturalmente, debe ajustar la instrucci´on path con la ubicaci´on de la m´aquina virtual en el computador donde vaya a ser ejecutado. Al final, si lo desea, puede eliminar los archivos .class que se han generado con una l´ınea adicional en el archivo .bat. Para Windows XP: rmdir /q/s EstrDatos
Para Windows 98: deltree /Y EstrDatos
Al terminar la compilaci´on, es necesario reemplazar el archivo EstrDatos.jar, almacenado en la ruta que le ha indicado al editor para que encuentre el paquete.
´ 13.3. DOCUMENTACION
13.3.
309
Documentaci´ on
Como se puede observar, el c´odigo fuente de las clases est´a documentado utilizando la sintaxis del paquete javadoc, la cual permite crear una serie de p´aginas Web con la informaci´on de las clases, con el formato de la ayuda de Java, lo que le da al paquete EstrDatos una presentaci´on est´andar. Si desea modificar los comentarios que se encuentran al inicio de cada m´etodo y generar de nuevo las p´aginas Web de documentaci´on, debe utilizar la siguiente instrucci´on: javadoc -d Doc -version -author *.java Para ejecutar esa instrucci´on, debe estar seguro de que la ruta donde se encuentra el programa javadoc est´a correctamente asociada con la variable path. Al ejecutar la instrucci´on de compilaci´on, se genera una carpeta llamada Doc y en ella, debe buscar el archivo index.htm, la p´agina inicial de la documentaci´on del paquete. La apariencia de la p´agina inicial se puede ver en las figuras 13.4, 13.5 y 13.6.
Figura 13.4: P´agina inicial de documentaci´on - 1
310
´ CAP´ITULO 13. CODIGO FUENTE
Figura 13.5: P´agina inicial de documentaci´on - 2
Figura 13.6: P´agina inicial de documentaci´on - 3 La documentaci´on se encuentra en la carpeta Documentacion en el CD que acompa˜ na este trabajo.
14
Pruebas
El c´odigo de pruebas autom´aticas se construy´o con el fin de verificar la consistencia de cada una de las estructuras de datos que componen este trabajo, buscando cubrir la mayor´ıa de situaciones posibles. El mayor beneficio de este tipo de pruebas es que se puede revisar muy r´apidamente si un cambio en el c´odigo de un m´etodo afecta a otro, simplemente ejecutando la prueba, porque la salida presenta el n´ umero de la prueba y el resultado de ella que puede ser OK o ERROR. El objetivo es que al finalizar cada programa, el resultado sea un n´ umero determinado de pruebas exitosas y cero errores. Las pruebas se realizaron haciendo seguimiento manual a cada caso de prueba. Antes de imprimir en pantalla cada mensaje, se hace una comparaci´on con el resultado esperado en ese momento. De esta manera, lo que sale en pantalla es f´acil de verificar y es una prueba que tiene vigencia en el tiempo. El c´odigo que se puede apreciar a continuaci´on permite realizar 18 pruebas a algunos m´etodos de la clase Node.java.
CAP´ITULO 14. PRUEBAS
312
PruebaNode.java import EstrDatos.*; import javax.swing.*; public class PruebaNode { public static void main ( String args[ ] ) { Node a,b,c; JTextArea area; JScrollPane scroll; int numero; int ok; int error; ok error
= 0; = 0;
area = new JTextArea ( 20, 10 ); scroll = new JScrollPane ( area ); try { a = new Node ( ); b = new Node ( "Bogota" ); c = new Node ( 3, "Medellin" ); // ----------------------------------------// Prueba No. 01 - Constructor con un parametros, isData if ( a.isData ( ) == false ) { area.append ( "01: OK\n" ); ok++; } else { area.append ( "01: ERROR\n" ); error++; }
313 // ----------------------------------------// Prueba No. 02 - Constructor sin parametros, getName if ( a.getName ( ).equals ( "noName" ) == true ) { area.append ( "02: OK\n" ); ok++; } else { area.append ( "02: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 03 - Constructor con un parametro, getName if ( b.getName ( ).equals ( "Bogota" ) == true ) { area.append ( "03: OK\n" ); ok++; } else { area.append ( "03: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 04 - Constructor con dos parametros, getName if ( c.getName ( ).equals ( "Medellin" ) == true ) { area.append ( "04: OK\n" ); ok++; } else { area.append ( "04: ERROR\n" ); error++; }
314
CAP´ITULO 14. PRUEBAS // ----------------------------------------// Prueba No. 05 - Constructor con dos parametros, getMaxPort if ( b.getMaxPort ( ) == 0 ) { area.append ( "05: OK\n" ); ok++; } else { area.append ( "05: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 06 - Constructor con dos parametros, getMaxPort if ( c.getMaxPort ( ) == 3 ) { area.append ( "06: OK\n" ); ok++; } else { area.append ( "06: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 07 - getNumberInputLinks if ( a.getNumberInputLinks ( ) == 0 ) { area.append ( "07: OK\n" ); ok++; } else { area.append ( "07: ERROR\n" ); error++; }
315 // ----------------------------------------// Prueba No. 08 - setName, getName a.setName ( "Armenia" ); if ( a.getName ( ).equals ( "Armenia" ) == true ) { area.append ( "08: OK\n" ); ok++; } else { area.append ( "08: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 09 - link, isLink a.link ( b, 1 ); if ( a.isLink ( 0 ) == false ) { area.append ( "09: OK\n" ); ok++; } else { area.append ( "09: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 10 - isLink if ( a.isLink ( 1 ) == true ) { area.append ( "10: OK\n" ); ok++; } else { area.append ( "10: ERROR\n" ); error++; }
CAP´ITULO 14. PRUEBAS
316
// ----------------------------------------// Prueba No. 11 - whoLink if ( a.whoLink ( 1 ) == b ) { area.append ( "11: OK\n" ); ok++; } else { area.append ( "11: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 12 - getNumberInputLinks if ( b.getNumberInputLinks ( ) == 1 ) { area.append ( "12: OK\n" ); ok++; } else { area.append ( "12: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 13 - getNumberInputLinks a.link ( b, 3 ); if ( b.getNumberInputLinks ( ) == 2 ) { area.append ( "13: OK\n" ); ok++; } else { area.append ( "13: ERROR\n" ); error++; }
317 // ----------------------------------------// Prueba No. 14 - getSize if ( a.getSize ( ) == 4 ) { area.append ( "14: OK\n" ); ok++; } else { area.append ( "14: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 15 - link, getLeastNumberPort a.link ( c, 0 ); if ( a.getLeastNumberPort ( ) == 2 ) { area.append ( "15: OK\n" ); ok++; } else { area.append ( "15: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 16 - unLink a.unLink ( 1 ); if ( a.isLink ( 1 ) == false ) { area.append ( "16: OK\n" ); ok++; } else { area.append ( "16: ERROR\n" ); error++; }
CAP´ITULO 14. PRUEBAS
318
// ----------------------------------------// Prueba No. 17 - getNumberInputLinks if ( b.getNumberInputLinks ( ) == 1 ) { area.append ( "17: OK\n" ); ok++; } else { area.append ( "17: ERROR\n" ); error++; } // ----------------------------------------// Prueba No. 18 - getNumberInputLinks if ( a.getOutputLinks ( ).equals ( "0: Medellin { null } " + "- [ 1.0 ]\n1: null\n2: null\n3: Bogota { null } - " + "[ 1.0 ]\n" ) == true ) { area.append ( "18: OK\n" ); ok++; } else { area.append ( "18: ERROR\n" ); error++; } // ----------------------------------------area.append area.append area.append area.append
( ( ( (
"\n" ); "Total pruebas: " + ( ok + error ) + "\n" ); "Total OK : " + ok + "\n" ); "Total ERROR: " + error + "\n" );
JOptionPane.showMessageDialog ( null, scroll, "Pruebas de nodos y enlaces", JOptionPane.INFORMATION_MESSAGE ); }
319 catch ( Exception exc) { JOptionPane.showMessageDialog ( null, exc.getMessage ( ), "Error", JOptionPane.ERROR_MESSAGE ); } System.exit ( 0 ); } }
La salida en pantalla del programa anterior se puede ver en la figura 14.1.
Figura 14.1: Pruebas
CAP´ITULO 14. PRUEBAS
320
En total se realizaron 360 pruebas diferentes, discriminadas as´ı: Librer´ıa Node.java SingleList.java DoubleList.java CircularSingleList.java CircularDoubleList.java Queue.java Stack.java Tree.java BinaryTree.java DirectedGraph.java UnDirectedGraph.java Total
N´ umero de pruebas 40 34 34 40 32 12 12 50 14 56 42 360
Para encontrar el c´odigo de prueba puede buscar en el CD que acompa˜ na este trabajo en la carpeta Pruebas, en la cual se pueden ver los archivos .jar que ejecutan las pruebas. Los nombres de los archivos de cada prueba inician con el prefijo Pr seguido del nombre de la estructura de datos o de las iniciales de la estructura (cuando es muy largo el nombre). Por ejemplo, PrAb.jar es el nombre del archivo que contiene las pruebas de ´arbol binario, PrLCSE.jar contiene las pruebas de lista circular sencillemente enlazada. Si desea verificar el c´odigo fuente de las pruebas, debe buscarlo en la carpeta Codigo Fuente y dentro de ella, en la carpeta Pruebas.
14.1.
Compilar un archivo de prueba
Los programas de prueba se pueden compilar y ejecutar como cualquier ejemplo de Java. Solo es necesario asegurarse de que el paquete EstrDatos est´e asociado con el editor para que las clases que componen el paquete le sea conocido. Sin embargo, los programas de prueba se han creado como archivos .jar. Un archivo .jar es un archivo comprimido que permite agrupar un conjunto de clases y los recursos asociados. En el caso de los programas de prueba,
14.1. COMPILAR UN ARCHIVO DE PRUEBA
321
solo se componen de un archivo .java y un archivo de manifiesto, llamado Manifest.MF. En el archivo de manifiesto se especifica el nombre de la clase que tiene el control de programa. En este caso, como hay una u ´nica clase, el nombre de ella tiene que ir en el archivo de manifiesto, lo mismo que el valor de la variable Class-Path. Si desea modificar un programa de pruebas y compilarlo de nuevo, es necesario tener en cuenta las siguientes instrucciones. Aseg´ urese de que la m´aquina virtual de Java (JVM) est´a asociada correctamente y en la ruta correcta. Compile los archivos.java correspondientes a la prueba, indicando donde se encuentra el paquete EstrDatos.jar y la carpeta donde se encuentra el c´odigo fuente de la prueba a compilar. Construir el archivo .jar en el cual se va a comprimir el archivo .class con el c´odigo binario del programa de prueba. Se debe especificar el archivo de manifiesto. Se le indica a la m´aquina virtual que el archivo va a ser ejecutable por s´ı solo, creando un ´ındice interno que optimiza la b´ usqueda de los archivos que componen el archivo comprimido. Si lo prefiere, puede crear un archivo .bat que facilite este proceso, con las siguientes instrucciones: path "D:\Archivos de programa"\"j2sdk1.4.1_02"\bin;c:\windows javac -g:none -d . -classpath EstrDatos.jar Lde\*.java jar cvfm PrLDE.jar Lde\Manifest.MF *.class jar -i PrLDE.jar
Naturalmente, debe ajustar la instrucci´on path con la ubicaci´on de la m´aquina virtual en el computador donde vaya a ser ejecutado. Al final, si lo desea, puede eliminar los archivos .class que se han generado con una l´ınea adicional en el archivo .bat. Para Windows XP: del /q *.class
Para Windows 98: del *.class
322
14.2.
CAP´ITULO 14. PRUEBAS
Ejecutar un archivo de prueba
Debido a que los archivos de prueba son archivos .jar ejecutables, se pueden poner en funcionamiento haciendo doble clic sobre ellos o con la siguiente instrucci´on en la l´ınea de comandos: javaw -jar PruebaNode.jar.
14.3.
Pruebas de compatibilidad
Los programas interactivos y los programas de pruebas fueron ejecutados exitosamente en diferentes plataformas. Se hicieron pruebas en Windows 98, Windows XP, Linux RedHat 9, MacOS X y Solaris 9. Ver figuras 14.2 y 14.3.
Figura 14.2: Pruebas en Linux
14.3. PRUEBAS DE COMPATIBILIDAD
Figura 14.3: Pruebas en Macintosh
323
324
CAP´ITULO 14. PRUEBAS
Parte V Ejercicios
325
15 Nodos
An´ alisis de c´ odigo fuente A continuaci´on, se pueden ver fragmentos de c´odigo de 15 programas sencillos que utilizan la librer´ıa Node.java. Algunos de estos programas son para analizar la salida. Otros son para verificar algunos errores y excepciones. En estos casos, se debe determinar porqu´e se han presentado y c´omo se pueden corregir. Para poder ejecutar el programa, deber´a escribirse dentro de un archivo con el nombre correspondiente.
CAP´ITULO 15. NODOS
328
Node01.java Determine la salida en pantalla.
import javax.swing.*; public class Nodo01 { public static void main ( String args[ ] ) { Node a, b, c; Integer temporal; JTextArea areaSalida; areaSalida = new JTextArea
( 10, 5 );
try { a = new Node ( ); b = new Node ( ); c = new Node ( ); a.set ( new Integer ( 7 ) ); b.set ( new Integer ( 5 ) ); a.link ( b, 0 ); a.link ( b, 4 ); a.link ( c, 1 ); b.link ( a, 0 ); c.link ( b, 1 ); if ( a.isLink ( 0 ) ) { a.unLink ( 0 ); } if ( a.isData ( ) == true ) { temporal = ( Integer ) a.get c.set ( temporal ); } areaSalida.append ( a.toString ( areaSalida.append ( "\n" ); areaSalida.append ( b.toString ( areaSalida.append ( "\n" ); areaSalida.append ( c.toString ( areaSalida.append ( "\n" );
( );
) ); ) ); ) );
329 JOptionPane.showMessageDialog( null, areaSalida, "Nodos", JOptionPane.INFORMATION_MESSAGE ); } catch ( Exception exc) { JOptionPane.showMessageDialog( null, exc.getMessage(), "Error", JOptionPane.ERROR_MESSAGE ); } } }
A partir del siguiente programa, solo se va a escribir el fragmento de c´odigo necesario para la prueba. No se van a considerar los errores por variables no declaradas. El ejemplo anterior puede servir de modelo si se desea poner en ejecuci´on en el computador.
Node02.java Determine la salida en pantalla. a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); ); ); );
cadenaSalida = ""; a.set ( new Integer ( 7 ) ); b.set ( new Character ( ’W’ ) ); c.set ( new String ( "Hola" ) ); d.set ( new Float ( 4.23 ) ); a.link ( b, 0 ); a.link ( c, 1 ); b.link ( c, 0 ); c.link ( b, 1 ); c.link ( d, 2 ); d.link ( a, 0 ); a.link ( b.whoLink ( 0 ), 2 ); d.whoLink ( 0 ).unLink ( 1 ); if ( c.getSize ( ) <= 3 ) { c.link ( b.whoLink ( 0 ).whoLink ( 2 ).whoLink ( 0 ), 1 ); } cadenaSalida += a + "\n" + b + "\n" + c + "\n" + d + "\n";
CAP´ITULO 15. NODOS
330
Node03.java Determine la salida en pantalla.
a b c d e
= = = = =
new new new new new
Node Node Node Node Node
( ( ( ( (
); ); ); ); );
a.set ( new Integer b.set ( new Integer c.set ( new Integer d.set ( new Integer e.set ( new Integer a.link ( b, 0 ); a.link ( c, 1 ); a.link ( e, 2 ); b.link ( a, 1 ); b.link ( c, 4 ); c.link ( d, 3 ); d.link ( b, 0 ); d.link ( e, 1 ); e.link ( b, 1 ); e.link ( c, 4 ); areaSalida.append (
( ( ( ( (
1 2 4 5 3
) ) ) ) )
); ); ); ); );
"\nValor a: " + a + "\n" );
Node04.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
Node Node Node Node
a.setName ( c.setName ( a.set ( new b.set ( new a.set ( new
( ( ( (
); "b" ); ); 3, "d" );
"a" ); "c" ); Integer ( 1 ) ); Integer ( 10 ) ); Integer ( 23 ) );
331 b.set ( new Integer ( 49 ) ); a.link ( b, 1 ); b.link ( c, 2, 7.1 ); areaSalida.append ( a.toString ( ) + "\n"); areaSalida.append ( b.toString ( ) + "\n"); areaSalida.append ( c.toString ( ) + "\n");
Node05.java Explique la raz´on por la cul se genera una excepci´on de n´ umero de puerto no v´alido.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.setName ( "a" ); c.setName ( "c" ); a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); b.link ( c, 2, 7.1 ); System.out.println ( "maxPort: d.link ( a, 3 ); areaSalida.append ( a.toString areaSalida.append ( b.toString areaSalida.append ( c.toString areaSalida.append ( d.toString
" + d.getMaxPort ( ) ); ( ( ( (
) ) ) )
+ + + +
"\n"); "\n"); "\n"); "\n");
CAP´ITULO 15. NODOS
332
Node06.java Al compilar el programa, se genera un error. Se˜ nale el error y explique porqu´e la raz´on.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.setName ( "a" ); c.setName ( "c" ); a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); b.link ( c, 2, 7.1 ); System.out.println ( "maxPort: d.setMaxPort ( a, 4 ); System.out.println ( "maxPort: d.link ( a, 3 ); areaSalida.append ( a.toString areaSalida.append ( b.toString areaSalida.append ( c.toString areaSalida.append ( d.toString
" + d.getMaxPort ( ) ); " + d.getMaxPort ( ) ); ( ( ( (
) ) ) )
+ + + +
"\n"); "\n"); "\n"); "\n");
Node07.java En este programa se genera una excepci´on. Explique la causa.
a b c d
= = = =
new new new new
Node Node Node Node
a.setName ( c.setName ( a.set ( new b.set ( new c.set ( new
( ( ( (
); "b" ); ); 3, "d" );
"a" ); "c" ); Integer ( 1 ) ); Integer ( 10 ) ); Integer ( 23 ) );
333 d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); b.link ( c, 2, 7.1 ); System.out.println ( "maxPort: d.setMaxPort ( 4 ); System.out.println ( "maxPort: d.setMaxPort ( 2 ); System.out.println ( "maxPort: d.link ( a, 1 ); areaSalida.append ( a.toString areaSalida.append ( b.toString areaSalida.append ( c.toString areaSalida.append ( d.toString
" + d.getMaxPort ( ) ); " + d.getMaxPort ( ) ); " + d.getMaxPort ( ) ); ( ( ( (
) ) ) )
+ + + +
"\n"); "\n"); "\n"); "\n");
Node08.java En este programa se genera una excepci´on. Explique la causa.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.setName ( "a" ); c.setName ( "c" ); a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); b.link ( c, 2, 7.1 ); d.setMaxPort ( 0 ); d.link ( a, 9 ); a.setWeight ( 0, 2.5 ); areaSalida.append ( a.toString areaSalida.append ( b.toString areaSalida.append ( c.toString areaSalida.append ( d.toString
( ( ( (
) ) ) )
+ + + +
"\n"); "\n"); "\n"); "\n");
CAP´ITULO 15. NODOS
334
Node09.java Al compilar el programa, se genera un error. Se˜ nale el error y explique porqu´e la raz´on.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.setName ( "a" ); c.setName ( "c" ); a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); b.link ( c, 2, 7.1 ); d.setMaxPort ( 0 ); d.link ( a, 9 ); a.setWeight ( 1, 2.5 ); System.out.println ( "El peso del enlace 1 del nodo a es: " + a.getWeight ( ) ); areaSalida.append ( a.toString ( ) + "\n"); areaSalida.append ( b.toString ( ) + "\n"); areaSalida.append ( c.toString ( ) + "\n"); areaSalida.append ( d.toString ( ) + "\n");
Node10.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
a.set b.set c.set d.set
( ( ( (
Node Node Node Node new new new new
( ( ( (
); "b" ); ); 3, "d" );
Integer Integer Integer Integer
( 1 ) ); ( 10 ) ); ( 23 ) ); ( 49 ) );
335 a.link ( b, 1 ); a.link ( c, 0 ); a.link ( d, 3 ); b.link ( c, 2, 7.1 ); System.out.println ( "El grado de entrada de c es: " + a.getNumberInputLinks ( ) );
Node11.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); a.link ( c, 0 ); a.link ( d, 3 ); b.link ( c, 2, 7.1 ); System.out.println ( "El puerto libre con indice menor" + " en el nodo a es: " + a.getLeastNumberPort ( ) );
Node12.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) );
CAP´ITULO 15. NODOS
336
d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); a.link ( c, 0 ); a.link ( d, 3 ); b.link ( c, 2, 7.1 ); areaSalida.append ( a.getOutputLinks ( ) );
Node13.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); a.link ( c, 0 ); a.link ( d, 3 ); b.link ( c, 2, 7.1 ); areaSalida.append ( "Enlaces que salen del nodo a: \n\n" ); areaSalida.append ( a.getOutputLinks ( ) );
Node14.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
a.set b.set c.set d.set
( ( ( (
Node Node Node Node new new new new
( ( ( (
); "b" ); ); 3, "d" );
Integer Integer Integer Integer
( 1 ) ); ( 10 ) ); ( 23 ) ); ( 49 ) );
337 a.link ( b, 1 ); a.link ( c, 0 ); a.link ( d, 3 ); b.link ( c, 2, 7.1 ); areaSalida.append ( "El nodo a esta conectado con \n" ); areaSalida.append ( "un nodo cuyo contenido es un Integer " ); areaSalida.append ( "con valor de 49\n en el puerto " ); areaSalida.append ( a.search ( new Integer ( 49 ) ) + "" );
Node15.java Determine la salida en pantalla.
a b c d
= = = =
new new new new
Node Node Node Node
( ( ( (
); "b" ); ); 3, "d" );
a.set ( new Integer ( 1 ) ); b.set ( new Integer ( 10 ) ); c.set ( new Integer ( 23 ) ); d.set ( new Integer ( 49 ) ); a.link ( b, 1 ); a.link ( c, 0 ); a.link ( d, 3 ); b.link ( c, 2, 7.1 ); areaSalida.append ( "El nodo b esta conectado con el nodo \n" ); areaSalida.append ( "c y un peso de 7.1\n" ); areaSalida.append ( "en el puerto " + b.search ( c, 7.1 ) );
Ejercicios de programaci´ on A continuaci´on se proponen algunos m´etodos que no se encuentran disponibles en la libreria Node.java y que deben ser desarrollados por los estudiantes. Debe construir un ejemplo de aplicaci´on que permita poner a prueba el funcionamiento de cada m´etodo que acaba de crear.
338
CAP´ITULO 15. NODOS
1. En el m´etodo isLink, se debe generar una excepci´on si se pasa por par´ametro un n´ umero de puerto no puede llegar a existir por la restricci´on del atributo maxPort. 2. En el m´etodo setMaxPort permitir que se disminuya el n´ umero m´aximo de puertos siempre y cuando se pierdan u ´nicamente puertos nulos o inexistentes. Debe ser posible realizar este cambio aunque el valor actual del atributo sea 0. 3. En el m´etodo setMaxPort permitir que el atributo maxPort pueda disminuir sin importar si se pierden nodos. En caso de que se pierdan nodos, debe verificar que los valores del grado de entrada de los nodos afectados no pierda consistencia. Debe ser posible realizar este cambio aunque el valor actual del atributo sea 0. 4. Escribir el m´etodo getNumberOutputLinks. 5. Escribir un m´etodo que agrupe los puertos no nulos en un nodo, dejando al final del vector los puertos nulos. 6. Escribir un m´etodo que permita obtener el puerto ocupado de un nodo con ´ındice mayor. En caso de que no tenga ninguno ocupado, debe retornar -1. 7. Crear el m´etodo unLink de manera que se desconecten todos los puertos de un nodo si no se especifica el n´ umero de puerto.
16 Lista
An´ alisis de c´ odigo fuente A continuaci´on, se pueden ver fragmentos de c´odigo de 3 programas sencillos que utilizan listas. Para poder ejecutar el programa, deber´a escribirse dentro de un archivo con el nombre correspondiente.
Lista01.java El siguiente fragmento de c´odigo fuente corresponde a una lista doblemente enlazada.
lista.add lista.insertLeft lista.insertRight lista.goFirst lista.insertRight lista.insertLeft
( ( ( ( ( (
new new new ); new new
Integer ( 5 ) ); Integer ( 3 ) ); Integer ( 7 ) ); Integer ( 3 ) ); Integer ( 3 ) );
CAP´ITULO 16. LISTA
340 lista.goNext lista.insertLeft lista.insertRight lista.insertLeft lista.insertRight n = lista.getIndex lista.goFirst lista.insertLeft lista.goTo
( ( ( ( ( ( ( ( (
); new Integer new Integer new Integer new Integer ); ); new Integer 4 );
numero = lista.goLast lista.insertLeft lista.goTo lista.remove lista.remove lista.remove lista.goNext lista.insertLeft lista.insertRight
( ( ( ( ( ( ( ( ( (
Integer ) lista.get ( ); ); numero ); 3 ); ); ); ); ); new Integer ( 3 ) ); new Integer ( 3 ) );
( ( ( (
3 3 1 3
) ) ) )
); ); ); );
( n ) );
Haga una prueba de escritorio paso a paso (con los dibujos que representan la lista). Diga cu´antos nodos tiene la lista al terminar. Diga si en la lista se almacena una referencia a un objeto de tipo Integer cuyo valor sea 7 y si es as´ı, diga en qu´e posici´on. Cu´al es valor entero del objeto cuya referencia se encuentra almacenada en el nodo de la posici´on actual. Cu´al es valor entero del objeto cuya referencia se encuentra almacenada en el u ´ltimo nodo de la lista. En qu´e posiciones de la lista se almacenan referencias a objetos Integer donde su contenido sea un 4. Qu´e valor hay en el objeto cuya referencia se encuentra a la izquierda del nodo que se encuentra a la izquierda del u ´ltimo nodo. Qu´e valor hay en el objeto cuya referencia se encuentra a la izquierda del nodo que se encuentra a la derecha del primer nodo.
341
Lista02.java El siguiente fragmento de c´odigo fuente corresponde a una lista doblemente enlazada. Determine la salida en pantalla.
lista.add lista.add lista.add lista.goNext lista.insertRight lista.goBack lista.goBack lista.remove lista.add lista.insertLeft lista.insertLeft lista.insertLeft lista.insertRight lista.add lista.goFirst lista.goBack lista.goBack lista.goBack lista.goBack lista.insertLeft lista.insertRight mensaje mensaje mensaje mensaje
+= += += +=
( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (
new new new ); new ); ); ); new new new new new new ); ); ); ); ); new new
Integer ( 19 ) ); Integer ( 23 ) ); Integer ( 2 ) ); Integer ( 10 ) );
Integer Integer Integer Integer Integer Integer
( 45 ) ); ( 5 ) ); ( 1 ) ); ( 5 ) ); ( 5 ) ); ( 12 ) );
Integer ( Integer (
7 ) ); 3 ) );
"La posicion actual es: " + lista.getIndex ( ) + "\n"; "El valor almacenado en la posicion actual es: "; lista.get ( ) + "\n"; lista.toString ( ) + "\n";
areaSalida.append ( mensaje );
CAP´ITULO 16. LISTA
342
Lista03.java El siguiente fragmento de c´odigo fuente corresponde a una lista doblemente enlazada. Determine la salida en pantalla.
lista.add lista.add lista.add lista.insertRight lista.add lista.insertLeft lista.insertLeft lista.insertLeft lista.insertRight lista.add lista.insertLeft lista.insertRight lista.goFirst
( ( ( ( ( ( ( ( ( ( ( ( (
new new new new new new new new new new new new );
Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer Integer
( ( ( ( ( ( ( ( ( ( ( (
19 23 2 10 45 5 1 5 5 12 7 3
) ) ) ) ) ) ) ) ) ) ) )
); ); ); ); ); ); ); ); ); ); ); );
for ( i = 0; i < 100; i++ ) { lista.goBack ( ); } lista.remove ( ); mensaje mensaje mensaje mensaje
+= += += +=
"La posicion actual es: " + lista.getIndex ( ) + "\n"; "El valor almacenado en la posicion actual es: "; lista.get ( ) + "\n"; lista.toString ( ) + "\n";
areaSalida.append ( mensaje );
Ejercicios de programaci´ on A continuaci´on se proponen algunos m´etodos que no se encuentran disponibles en las diferentes librer´ıas de listas. Debe construir un ejemplo de aplicaci´on que permita poner a prueba el funcionamiento de cada m´etodo que acaba de crear.
343 insertar ( posicion, elemento );, donde posicion especifica el ´ındice del nodo nuevo el cual tendr´a en el campo de datos una referencia al objeto elemento. Si la posici´on no existe en la lista se debe generar una excepci´on. insertar ( posicion, veces, elemento );, donde posicion especifica el ´ındice del nodo nuevo el cual tendr´a en el campo de datos una referencia al objeto elemento; veces indica el n´ umero de veces que se debe insertar el elemento en la lista. Si la posici´on no existe en la lista se debe generar una excepci´on. eliminar ( elemento );, donde elemento especifica un objeto que se debe buscar en la lista para eliminarlo. Se debe eliminar la primera aparici´on del elemento especificado. Debe utilizar el m´etodo equals para determinar si dos objetos son equivalentes. Si el elemento no existe en la lista se debe generar una excepci´on. eliminar ( elemento );, donde elemento especifica un objeto que se debe buscar en la lista para eliminarlo. Se debe eliminar la u ´ltima aparici´on del elemento especificado. Si el elemento no existe en la lista se debe generar una excepci´on. eliminar ( elemento );, donde elemento especifica un objeto que se debe buscar en la lista para eliminarlo. Se deben eliminar todas las apariciones del elemento especificado. Si el elemento no existe en la lista se debe generar una excepci´on. eliminar ( posicion );, donde posicion especifica el ´ındice del nodo que se va a eliminar. Si la posici´on no existe en la lista se debe generar una excepci´on. eliminar ( posicionInicial, posicionFinal );, donde los par´ametros especifican el inicio y el final del rango de elementos de la lista que se deben eliminar. Si alguna de las posiciones no existe en la lista se debe generar una excepci´on.
Aplicaciones A continuaci´on se enumera una lista de aplicaciones sencillas en las cuales se pueden poner en pr´actica las habilidades de programaci´on de los estudiantes
344
CAP´ITULO 16. LISTA
para construir programas con estructuras de datos. 1. Dada una lista de 50 enteros generada al azar con elementos entre 1 y 100, dividirla en dos listas, una con los elementos de las primeras 25 posiciones y otra con el resto de los elementos de la lista. 2. Dada una lista de 50 enteros generada al azar con elementos entre 1 y 100, dividirla en dos listas, una con los elementos de las posiciones pares y otra con los elementos de las posiciones impares. 3. Dada una lista de 50 enteros generada al azar con elementos entre 1 y 100, dividirla en dos listas, una con los elementos pares y otra con los elementos impares. 4. Dada una lista de 50 enteros generada al azar con elementos entre 1 y 100, dividirla en dos listas, una con los elementos que est´an en el promedio o por debajo y otra con los elementos que est´an por encima. No olvide que el promedio es un n´ umero flotante. 5. Dada una lista ordenada de menor a mayor con 50 enteros generada al azar con valores entre 1 y 100, dividirla en dos listas, una con los elementos que est´an en la mediana o por debajo y otra con los elementos que est´an por encima. 6. Crear un programa que lea por teclado n´ umeros enteros en una GUI. La lista deber´a permanecer ordenada de menor a mayor. 7. Dada una lista de 30 enteros generada al azar con elementos entre 1 y 20, generar otra lista con los elementos repetidos de la primera. 8. Dada una lista de 50 enteros generada al azar con elementos entre 1 y 100, calcular la suma de los elementos de las posiciones pares y de las posiciones impares. 9. Dada una lista de 50 enteros generada al azar con elementos entre 1 y 100, calcular la suma de los elementos pares y de los elementos impares. 10. Dada una lista de enteros con 100 numeros generados al azar entre 0 y 9, forme una lista de casillas donde la posici´on en la lista corresponde al n´ umero generado y el valor almacenado en el nodo de esa posici´on corresponde al n´ umero de veces que dicho numero aparece en la lista.
345 Debe crear una lista de casillas equivalente a la original, de manera que se pueda reconstruir en forma ordenada de menor a mayor. Por ejemplo (con n´ umeros entre 0 y 4) tendr´ıamos: lista = { 4, 1, 1, 2, 3, 4, 1, 4, 3, 2, 2, 2, 2, 3, 1}, con 15 elementos. La lista de casillas indica que en la posici´on 0 hay un 0 porque el n´ umero 0 est´a 0 veces. En la posici´on 1 debe guardarse un 4 porque el 1 est´a 4 veces en la lista. De igual manera, en la posici´on 2, se almacena un 5, porque el 2 est´a 5 veces y as´ı sucesivamente. La lista de casillas tendr´ıa los siguientes elementos: casillas = {0, 4, 5, 3, 3 }. Si se fuera a ver la lista inicial ordenada, ser´ıa: ordenada = {1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4}
Proyectos peque˜ nos A continuaci´on se enumera una lista de proyectos que pueden servir para que el estudiante afiance los conceptos de programaci´on con estructuras de datos. 1. Genere una lista con las siguientes secuencias de n´ umeros enteros: 1 1 2 2 3 3 4 4 5 5 6 6 . . . 1 2 3 4 5 1 2 3 4 5 1 2 . . . 0 0 1 0 0 1 0 0 1 0 0 1 . . . En cada caso, debe considerarse el n´ umero de elementos que el usuario quiere para la lista.
346
CAP´ITULO 16. LISTA
2. Ingrese n´ umeros enteros a una lista y encuentre el mayor, el menor, el promedio (n´ umero flotante) y la suma.
3. Construya un programa que genere una lista de n´ umeros enteros al azar, con 20 elementos del 1 al 15. Debe generar otra lista la cual corresponde a la primera pero sin n´ umeros repetidos.
347
4. Investigue los algoritmos de ordenamiento por burbuja, selecci´on directa e inserci´on directa y construya una aplicaci´on de estos algoritmos para ordenar de menor a mayor una lista de n´ umeros enteros generada al azar con 30 elementos entre el 1 y el 50.
5. Intercale el contenido de dos listas de enteros ya ordenadas (generadas al azar) en una tercera lista con los elementos de las otras dos listas, la cual quedar´a ordenada sin utilizar algoritmos de ordenamiento.
348
CAP´ITULO 16. LISTA
6. Construya una GUI en la cual se puedan poner en funcionamiento todos los m´etodos que ofrece la API de lista (cualquiera de las cuatro clases de listas). El objetivo del programa es hacer una lista de fotos o archivos con extensi´on .jpg o .gif. Las im´agenes deben estar almacenadas en un disco y el programa debe tener la posibilidad de seleccionarlas entre la lista de archivos. Debe ser posible guardar la lista en un archivo. Puede usar botones, men´ us o barras de herramientas, de acuerdo al dise˜ no que desee.
17 Cola
Ejercicios de programaci´ on A continuaci´on se proponen algunos m´etodos que no se encuentran disponibles en la librer´ıa de colas. Debe construir un ejemplo de aplicaci´on que permita poner a prueba el funcionamiento de cada m´etodo que acaba de crear. Haga una modificaci´on a la librer´ıa de colas, de manera que adem´as de tener como atributo una lista doblemente enlazada, tenga otro atributo un entero que puede llamar capacidad. El objetivo es que redefina completamente la librer´ıa para que se evite el desbordamiento. El desbordamiento ocurrir´ıa si la cantidad de elementos de la cola es mayor que la capacidad. Debe existir un m´etodo constructor de la cola que fije dicha capacidad. Construya una librer´ıa de clase llamada Biqueue.java que permita crear una cola doble. La cola doble tiene los mismos m´etodos que la cola, simplemente se le debe indicar si un elemento a insertar o a remover
CAP´ITULO 17. COLA
350
de ella se hace por la derecha o por la izquierda. Puede usar constantes RIGHT o LEFT.
Proyectos peque˜ nos A continuaci´on se enumera una lista de proyectos que pueden servir para que el estudiante afiance los conceptos de programaci´on con estructuras de datos. 1. Construya una GUI en la cual se puedan poner en funcionamiento todos los m´etodos que ofrece la API Queue. El objetivo del programa es hacer un visualizador de una cola de fotos o archivos con extensi´on .jpg o .gif. Las im´agenes deben estar almacenadas en un disco y el programa debe tener la posibilidad de seleccionarlas entre la lista de archivos. Debe ser posible guardar la cola en un archivo. Puede usar botones, men´ us o barras de herramientas, de acuerdo al dise˜ no que desee. 2. Construya un programa que inserte a una cola la baraja completa de un naipe de Poker, listo para repartir las cartas, es decir, un naipe barajado. Puede utilizar los componentes gr´aficos que desee de acuerdo con el dise˜ no previo que haga.
18 Pila
Ejercicios de programaci´ on A continuaci´on se proponen algunos m´etodos que no se encuentran disponibles en la librer´ıa de pilas. Debe construir un ejemplo de aplicaci´on que permita poner a prueba el funcionamiento de cada m´etodo que acaba de crear.
Haga una modificaci´on a la librer´ıa de pilas, de manera que adem´as de tener como atributo una lista sencillamente enlazada, tenga otro atributo un entero que puede llamar capacidad. El objetivo es que redefina completamente la librer´ıa para que se evite el desbordamiento. El desbordamiento ocurrir´ıa si la cantidad de elementos de la pila es mayor que la capacidad. Debe existir un m´etodo constructor de la pila que fije dicha capacidad.
CAP´ITULO 18. PILA
352
Aplicaciones A continuaci´on se enumera una lista de aplicaciones sencillas en las cuales se pueden poner en pr´actica las habilidades de programaci´on de los estudiantes para construir programas con estructuras de datos. 1. Escriba un programa que permita invertir el contenido de una lista doblemente enlazada usando una pila. 2. Escriba un programa que compruebe el balance de s´ımbolos de agrupaci´on en una expresi´on. Debe considerar los siguientes s´ımbolos: {} [] () <>. El resultado esperado es: OK Falta s´ımbolo de apertura Falta s´ımbolo de cierre En este ejercicio, todo s´ımbolo { debe tener asociado otro s´ımbolo }. Igual sucede con [ ], ( ) y < >. Contar el n´ umero de apariciones de cada s´ımbolo no es suficiente. Por ejemplo, la secuencia [ ( ) ] es correcta, pero [ ( ] ) no lo es. Algoritmo Inicializar una pila vac´ıa. Ingresar una expresi´on infija, como cadena de caracteres. Analizar cada s´ımbolo de la expresi´on: Si el s´ımbolo es de apertura, se agrega a la pila. Si el s´ımbolo es de cierre y la pila est´a vac´ıa, se produce un error. Si el s´ımbolo es de cierre y la pila no est´a vac´ıa, se obtiene y elimina el primer elemento de la pila. Si el s´ımbolo obtenido no es el esperado (de acuerdo con el s´ımbolo de cierre), se produce un error. Al final, si la pila est´a vac´ıa, se produce un resultado exitoso. En otro caso, se produce un error porque faltan s´ımbolos de cierre. Nota: Si el resultado es un error, debe indicarse el s´ı esperado.
353 3. Escriba un programa que permita convertir una expresi´on aritm´etica infija en posfija. Una expresi´on posfija est´a formada por una serie de operadores y operandos, sin par´entesis. Una expresi´on posfija no necesita reglas de precedencia. Por ejemplo, 1 2 3 * + es una expresi´on posfija, equivalente a la expresi´on infija 1 + 2 * 3. Para la conversi´on se eval´ uan los caracteres de la expresi´on en forma individual, de tal manera que la salida tenga los n´ umeros (operandos) y los operadores separados por espacios en blanco. Esta separaci´on permite diferenciar los n´ umeros de un solo d´ıgito con respecto a los que tienen m´as de un d´ıgito. En caso de que el caracter sea un operando, va directamente a la cadena de salida. Si es operador ( +, -, *, /, ^), elimina de la pila y agrega a la cadena de salida todos los operadores con precedencia MAYOR o IGUAL a la precedencia del elemento de la f´ormula. A continuaci´on, agrega el elemento de la f´ormula a la pila. Si el elemento de la f´ormula es ( se considera de mayor precedencia cuando est´a en la f´ormula, pero de menor precedencia si est´a en la pila. Es decir, se agrega inmediatamente a la pila. Solo se elimina de la pila cuando en la f´ormula se encuentre un ). Si es ) deber´a desapilar s´ımbolos hasta encontrar un ( y agregarlos a la cadena de salida. Recuerde que a la cadena de salida no se le adicionan par´entesis. Al terminar de evaluar la cadena de entrada, se desocupa la pila, leyendo el primer elemento de la pila, elimin´andolo y agreg´andolo a la cadena de salida en la que se almacena la expresi´on posfija. Nota: Debe insertar espacios en blanco en la cadena de salida antes de procesar un operador y despu´es de adicionar a la cadena de salida un elemento que viene de la pila. Por ejemplo, 800 - 2 ^ 3 ^ 2 + ( 10 - 5 * 6 ) / 4 es equivalente a 800 2 3 ^ 2 ^ - 10 5 6 * - 4 / +. 4. Escriba un programa que permita resolver una expresi´on aritm´etica posfija.
CAP´ITULO 18. PILA
354
Para evaluar una expresi´on posfija, se debe seguir el siguiente algoritmo. Inicializar una pila vac´ıa. Ingresar la expresi´on posfija, separando cada operando y operador por un espacio en blanco. Analizar cada token de la cadena: Si es un n´ umero, se agrega a la pila. Si es un operador, se sacan de la pila dos operandos, se aplica la operaci´on (de acuerdo al operador obtenido) y el resultado se agrega a la pila. Tenga en cuenta que el primer operando retirado de la pila corresponde al argumento derecho de la operaci´on. El argumento izquierdo de operaci´on es el segundo n´ umero retirado de la pila. Al terminar, solo un elemento debe quedar en la pila, el cual corresponde al resultado de la expresi´on posfija. Si antes de obtener el resultado final de la expresi´on la pila est´a vac´ıa, se produce un error. Finalmente, si al obtener el resultado, elimin´andolo de la pila, la pila no termina vac´ıa, se produce un error. El resultado de la expresi´on: 800 2 3 ^ 2 ^ - 10 5 6 * - 4 / + es 731. Nota: Debe utilizar la clase StringTokenizer de Java para capturar un token de la expresi´on infija.
String cadena; StringTokenizer cadenaCompleta; cadena = "800 10 20 30 35"; cadenaCompleta = new StringTokenizer ( cadena ); while ( cadenaCompleta.hasMoreTokens ( ) == true ) { cadena = cadenaCompleta.nextToken ( ); System.out.println ( cadena ); }
355
Proyectos peque˜ nos A continuaci´on se enumera una lista de proyectos que pueden servir para que el estudiante afiance los conceptos de programaci´on con estructuras de datos. 1. Construya una GUI en la cual se puedan poner en funcionamiento todos los m´etodos que ofrece la API Stack. El objetivo del programa es hacer un visualizador de una pila de fotos o archivos con extensi´on .jpg o .gif. Las im´agenes deben estar almacenadas en un disco y el programa debe tener la posibilidad de seleccionarlas entre la lista de archivos. Debe ser posible guardar la pila en un archivo. Puede usar botones, men´ us o barras de herramientas, de acuerdo al dise˜ no que desee.
356
CAP´ITULO 18. PILA
19 ´ Arbol
Ejercicios de programaci´ on A continuaci´on se proponen algunos m´etodos que no se encuentran disponibles en la librer´ıa de ´arboles n-arios. Debe construir un ejemplo de aplicaci´on que permita poner a prueba el funcionamiento de cada m´etodo que acaba de crear. Construir un m´etodo que permita ir a un hermano, especificando su ´ındice en el par´ametro. En caso de que no exista, lanza una excepci´on. Construir un metodo que permita ir al abuelo. En caso de que no exista, lanza una excepci´on. Construir un m´etodo que permita ir a un t´ıo, especificando su ´ındice en el par´ametro. En caso de que no exista, lanza una excepci´on. Construir un m´etodo que permita eliminar un hermano, especificando su ´ındice en el par´ametro. En caso de que no exista, lanza una excepci´on.
358
´ CAP´ITULO 19. ARBOL Construir un m´etodo que permita eliminar un t´ıo, especificando su ´ındice en el par´ametro. En caso de que no exista, lanza una excepci´on. Construir un m´etodo que permita mover un nodo como el hijo especificado de otro nodo. Debe moverse con todos sus descendientes. Si existe el hijo especificado, debe sobreescribirse. Si no existe, debe crearse. Construir un m´etodo que permita saber si el nodo actual es hijo u ´nico o no. Construir un m´etodo que permita saber si un nodo es ancestro de otro o no. Los dos nodos deben pasar por par´ametro. Construir un m´etodo que permita saber el n´ umero de primos hermanos del nodo actual. Construir un m´etodo que permita conocer el n´ umero de sobrinos del nodo actual. Construir un m´etodo que permita saber el n´ umero de nietos del nodo actual. Construya un m´etodo que permita conocer el n´ umero de hijos del nodo actual que tienen hijos. Construya un m´etodo que permita conocer el nivel del nodo actual. Construya un m´etodo que permita conocer el n´ umero de nodos que est´an al mismo nivel en el ´arbol. Construya un m´etodo que diga si existe un hijo con un contenido especificado en el par´ametro. En caso existir, debe retornar el ´ındice. Si no, debe retornar -1. Construya un m´etodo que diga si existe un descendiente con un contenido especificado en un String. el par´ametro. En caso existir, debe retornar la referencia al nodo. Si no, debe retornar null. Construya un m´etodo que permita saber si una lista de nodos constituye un camino v´alido entre dos nodos. Construya un m´etodo que permita obtener la direcci´on del primer ancestro com´ un a dos nodos.
359
Aplicaciones A continuaci´on se enumera una lista de aplicaciones sencillas en las cuales se pueden poner en pr´actica las habilidades de programaci´on de los estudiantes para construir programas con estructuras de datos. 1. Haga un programa que dado un ´arbol n-ario de enteros construya una lista que almacene los elementos pares. 2. Haga un programa que dado un ´arbol n-ario de enteros construya una lista que almacene los elementos del ´arbol, ordenados de menor a mayor por cualquier m´etodo de ordenamiento. 3. Construya un programa que cree un ´arbol n-ario con 3 niveles m´ınimo, con un n´ umero de hijos al azar y con un n´ umero entero al azar en cada nodo.
360
´ CAP´ITULO 19. ARBOL
20 Grafo
An´ alisis de c´ odigo fuente A continuaci´on, se pueden ver fragmentos de c´odigo de 3 programas sencillos que utilizan listas. Para poder ejecutar el programa, deber´a escribirse dentro de un archivo con el nombre correspondiente.
GrafoD01.java Determine la salida en pantalla.
grafo = new DirectedGraph ( ); grafo.add ( "a", new Integer ( 2 ) ); grafo.add ( "b", new Integer ( 10 ) ); grafo.add ( "c", new Integer ( 9 ) ); grafo.link ( "a", "b", 1, 2.3 );
CAP´ITULO 20. GRAFO
362 grafo.link ( "b", "c", 0 ); grafo.link ( "c", "a", 3, 3.8 ); grafo.setWeight ( "b", 0, 2.1 ); grafo.unLink ( "a", 1 ); grafo.link ( "b", "a", 3, 1.5 ); areaSalida.append ( grafo.toString ( ) );
GrafoD02.java Determine la salida en pantalla.
grafo = new DirectedGraph ( ); grafo.add grafo.add grafo.add grafo.add grafo.link grafo.link grafo.link grafo.link grafo.link grafo.link grafo.link
( ( ( (
"a", "b", "c", "d", ( ( ( ( ( ( (
"a", "a", "b", "c", "c", "d", "a",
new new new new
Integer Character String Float
( 7 ) ( ’W’ ) ( "Hola" ) ( 4.23 )
); ); ); );
"b", 0 ); "c", 1 ); "c", 0 ); "b", 1 ); "d", 2 ); "a", 0 ); grafo.whoLink ( "b", 0 ).getName ( ), 2 );
grafo.unLink ( grafo.whoLink ( "d", 0 ).getName ( ), 1 ); if ( grafo.getSizeNode ( "c" ) <= 3 ) { grafo.link ( "c", grafo.whoLink ( "b", 0 ).whoLink ( 2 ) .whoLink ( 0 ).getName ( ), 1 ); } areaSalida.append ( grafo.toString ( ) );
363
GrafoND01.java Determine la salida en pantalla.
grafo = new UnDirectedGraph ( ); grafo.add grafo.add grafo.add grafo.add
( ( ( (
"a", "b", "c", "d",
grafo.link ( grafo.link ( grafo.link ( grafo.link ( grafo.link ( grafo.unLink grafo.unLink
new new new new
Integer Integer Integer Integer
( 2 ), 4 ); ( 10 ) ); ( 9 ) ); ( 43 ) );
"a", "b", 1, 2.3 ); "b", "c", 1, 3.2 ); "c", "a", 3, 3.8 ); "c", "d" ); "a", "b" ); ( "a", 0 ); ( "a", 1 );
areaSalida.append ( grafo.toString ( ) );
GrafoND02.java Determine la salida en pantalla.
grafo = new UnDirectedGraph ( ); grafo.add grafo.add grafo.add grafo.add
( ( ( (
"a", "b", "c", "d",
new new new new
Integer Character String Float
( 7 ) ( â&#x20AC;&#x2122;Wâ&#x20AC;&#x2122; ) ( "Hola" ) ( 4.23 )
); ); ); );
grafo.link ( "a", "b", 0 ); grafo.link ( "a", "c", 1 ); grafo.link ( "b", "c", 0 ); grafo.link grafo.link grafo.link grafo.link
( ( ( (
"c", "c", "d", "a",
"b", 1 ); "d", 2 ); "a", 0 ); grafo.whoLink ( "b", 0 ).getName ( ), 2 );
364
CAP´ITULO 20. GRAFO
grafo.unLink ( grafo.whoLink ( "d", 0 ).getName ( ), 1 ); if ( grafo.getSizeNode ( "c" ) <= 3 ) { grafo.link ( "c", grafo.whoLink ( "b", 0 ).whoLink ( 2 ) .whoLink ( 0 ).getName ( ), 1 ); } areaSalida.append ( grafo.toString ( ) + "\n" + mensaje);
Aplicaciones A continuaci´on se enumera una lista de aplicaciones sencillas en las cuales se pueden poner en pr´actica las habilidades de programaci´on de los estudiantes para construir programas con estructuras de datos. 1. Construya un grafo de n nodos, donde el usurio determina el n´ umero de nodos (m´ınimo 3). El grafo debe conectar cada nodo con todos los dem´as.
Conclusiones Las diferentes construcciones que se pueden realizar a partir de la combinaci´on de nodos y enlaces son de mucha utilidad en las ciencias de la computaci´on. Las librer´ıas de clase construidas en Java aportan innumerables fortalezas para su aplicaci´on en diferentes escenarios. Gracias a la forma como se ha ilustrado este trabajo, es posible ver los detalles que se manejan al interior de cada operaci´on en las diferentes estructuras de datos que hacen parte de este trabajo. El paquete EstrDatos crea una capa de abstracci´on de m´as alto nivel, lo cual facilita su aplicaci´on en la soluci´on de problemas pr´acticos. A pesar de que el paquete EstrDatos define diez (10) estructuras de datos distintas, cada una de ellas se puede analizar, estudiar y utilizar de manera independiente. Gracias a la forma como se ha realizado el an´alisis de las diferentes estructuras de datos, la implementaci´on de ellas se puede realizar f´acilmente en otros lenguajes de programaci´on modernos como C#. Este material puede servir para que estudiantes en otros cursos como Matem´atica Discreta construyan nuevos algoritmos y puedan realizar aplicaciones u ´tiles a la sociedad.
366
CONCLUSIONES El uso de Java como lenguaje de programaci´on, m´as el uso del material de apoyo ha sido importante inclusive en cursos de semestres avanzados, donde se aplican las estructuras de datos, debido a que los estudiantes utilizan las APIs como herramienta de trabajo en los proyectos. Los programas interactivos facilitan la comprensi´on del funcionamiento de cada una de las estructuras de datos que hacen parte de este trabajo. Los estudiantes pueden hacer seguimiento de las instrucciones que se ejecutan y la secuencia en la cual se deben escribir, usando los archivos de historial de los programas interactivos. El c´odigo fuente utilizado ha tratado de ser lo m´as limpio posible y f´acil de entender. Adem´as, se utiliza un est´andar de codificaci´on muy aceptado a nivel mundial, con identificadores en ingl´es y sin abreviaturas, con el fin de facilitar el estudio y aprendizaje de las APIs que conforman el paquete EstrDatos. El uso del est´andar de codificaci´on usado por desarrolladores de Java, y utilizado en el paquete EstrDatos, con identificadores en ingl´es y sin abreviaturas, permite familiarizar al estudiante con la documentaci´on que puede encontrar en otros paquetes que ofrece Java. El uso que los estudiantes de tercer semestre de pregrado en Ingenier´ıa de Sistemas y Computaci´on de la Universidad del Quind´ıo le han dado a este material, ha permitido proyectos de fin de semestre m´as complejos que cuando se orientaba la asignatura en forma tradicional. Despu´es de tener la experiencia de nueve grupos consecutivos orientando el curso de Estructuras de Datos, puedo afirmar que el material construido ha contribuido para abarcar mayor cantidad de temas y tener estudiantes m´as motivados.
Bibliograf´ıa [1] BECERRA, C´esar. Estructuras de datos en C++. Segunda Edici´on. Por computador Ltda. Bogot´a, 1998. [2] BECERRA, C´esar. Estructuras de datos en Java. Segunda Edici´on. Por computador Ltda. Bogot´a, 2000. [3] CEBALLOS, Francisco. Curso de programaci´ on en Java 2. Segunda edici´on. Alfaomega Grupo Editor. M´exico, 2003. [4] FROUFE, Agust´ın. Java 2 Manual de usuario y tutorial. Alfaomega Grupo Editorl. M´exico, 2000. ´ ´ [5] GOMEZ, Carlos E.y GUTIERREZ, Juli´an E. Java 1.3 Volumen I: Fundamentos. POL Editores. Armenia, 2001. ´ ´ [6] GOMEZ, Carlos E.y GUTIERREZ, Juli´an E. Herramienta de Desarrollo Orientada a Objetos para desarrollar aplicaciones con Estructuras de Datos. Universidad del Quind´ıo, 2001. [7] GOODRICH, Michael y TAMASSIA, Roberto. Estructuras de Datos y Algoritmos en Java. Primera edici´on en espa˜ nol, CECSA, M´exico, 2002.
367
368
BIBLIOGRAF´IA
[8] JOYANES, Luis. Programaci´ on en C++. Algoritmos, estructuras de datos y objetos. McGraw-Hill, Madrid, 2000. [9] JOYANES, Luis. Fundamentos de programaci´ on. Algoritmos, y estructuras de datos. Segunda edici´on. McGraw-Hill, Madrid, 1999. ´ [10] JOYANES, Luis y FERNANDEZ, Matilde. Java 2 Manual de programaci´ on. McGraw-Hill, Madrid, 2001. [11] JOYANES, Luis y otros. Estructura de datos: Libro de problemas. McGraw-Hill, Madrid, 1999. [12] LANGSAM, Yedidyah, AUGENSTEIN, Moshe y TENENBAUM, Aaron. Estructuras de datos con C y C++. Segunda edici´on. Prentice Hall. M´exico, 1997. [13] LARMAN,Craig. UML Introducci´ on al an´alisis y dise˜ no orientado a objetos. Pretice Hall, M´exico, 1999. [14] SCHILDT, Herbert. Java 2: Manual de Referencia. Cuarta edici´on. McGraw-Hill. Madrid, 2001. [15] SCHILDT, Herbert. Fundamentos de programaci´ on en Java 2. McGraw-Hill. Bogot´a, 2001. [16] SISA, Alberto Jaime. Estructuras de datos y algoritmos con ´enfasis en programaci´ on orientada a objetos. Prentice Hall. Bogot´a, 2002. [17] WEISSS, Mark Allen. Estructuras de datos en Java. Addison Wesley. Madrid, 2000.