You are on page 1of 291
Eee La ie DLS reas EIS ONC A ESTRUCTURAS DE DATOS Y ALGORITMOS ROBERTO HERNANDEZ JUAN CARLOS LAZARO RAQUEL DORMIDO SALVADOR ROS Departamento de Informitica y Automatica UNIVERSIDAD NACIONAL DE EDUCACION A DISTANCIA PRENTICE HALL Madrid # México # Santafé de Bogota * Buenos Aires # Caracas ¢ Lima ¢ Montevideo « San Juan San José # Santiago # Sao Paulo ¢ White Plains datos de eatalogacion bibiogratica ESTRUCTURAS DE DATOS Y ALGORITMOS Hernindez, R.; Lizaro, J. C.; Dormido, R.; Ros, 8. PEARSON EDUCACION, S.A., Madrid, 2001 ISBN: 84-205-2980-X Materia: Informatica. 681.3 Formato 170 x 240 Paginas: 296 ESTRUCTURAS DE DATOS Y ALGORITMOS Hernandez, R.; Lazaro, J. C.; Dormide, R.; Ros, S. No esta permitida la reproduccién total o parcial de esta obra ni su tratamiento o transmisiGn por cualquier medio 0 método, sin autorizaci6n escrita de la Editorial. DERECHOS RESERVADOS © 2001 respecto a la edicién en espaiiol por: PEARSON EDUCACION, S.A. Nijiez de Balboa, 120 28006 MADRID ISBN: 84-205-2980-X Depésito legal: M. 33.933-2000 PRENTICE HALL es un sello editorial autorizado de PEARSON EDUCACION, S. A. Editor: Andrés Otero Asistente editorial: Ana Isabel Garcfa Impreso por: IMPRESO EN ESPANA - PRINTED IN SPAIN Este libro ha sido impreso con papel y tintas ecoldgico Indice general Prélogo ix Introduccién y conceptos fundamentales 1 11 12 13 14 Estructuras de datos Estructuras de datos y tipos de datos abstractos 3. Tipos de datos abstractos: Puntero y Listas enlazadas .2.4 Listas enlazadas 5 Insercién por la cabeza . Inserci6n por el final Suprimir por la cabeza . Suprimir por el final . Inserci6n segtin un criterio de orden . Imprimir una lista enlazada 1.2.5 TDA Lista implementado con listas enlazadas Algoritmos . . Conclusiones Clasificacién en memoria principal 45 21 2.2 Introduccién Métodos directos de clasificacién 2.2.1 Clasificacién por insercién directa Anilisis de la clasificacion por insercién directa . . . vi {NDICE GENERAL 2.2.2 Clasificacién por insercién binaria ‘Andlisis de la clasificacién por insercién binaria . . 55 2.2.3 Clasificacién por selec« 57 Anilisis de la clasificacién por seleccién directa . 59 2.2.4. Clasificacién por intercambio directo ..... - 62 Anilisis de la clasificaci6n por intercambio directo. + 64 2.2.5 Clasificacién por sacudida o vibracién 66 Andlisis de la clasificacién por vibracién - 68 2.2.6 Comparacién de los métodos directos de clasificacién . 69 2.3. Métodos avanzados de clasificacién .. . :70 2.3.1 Insercién por incremento decreciente --70 Anilisis de la clasificaci6n Shell . 72 2.3.2 Clasificacién por mont6n . aoe} Anélisis de la clasificacién por monton . 81 2.3.3 Clasificacién por particién . 82 Anilisis de la clasificaci6n por particién - 86 CaAlculo del k-ésimo mayor elemento . . 89 2.3.4 Comparacién de los métodos avanzados de clasificacién . . 90 2.4 Conclusiones 91 3 Clasificacion en memoria secundaria 93 3.1 Introduccién 93 3.2 clasificacién extema basada en mezcla . - 95 3.2.1 Mezcla directa 95 ‘Andlisis de la mezcla directa. 101 3.3 3.4 3.5 3.2.2, Mezcla natural Andlisis de la mezcla natural . 3.2.3. Mezcla balanceada multiple Consideraciones sobre la implementacién . Anilisis de la mezcla balanceada multiple . 3.2.4 Clasificacién polifésica .... Consideraciones sobre la implementacién . Archivos indexados .... Tablas de dispersi6n (Hashing) 3.4.1 Funciones Hash 3.4.2 Manejo de desbordamiento 0 sobrecarga . Anilisis de las tablas hash . Conclusiones . . 116 116 122 AL 4.2 43 44 . 4.6 47 5. 5.2 5. io 5.4 ae in 5.6 vii Tipos de datos abstractos dindmicos lineales 143 Introduccién . . Ejemplos de TDA dindmicos lineales . Pilas 4.3.1 Implementacién de pilas mediante arreglos . 4.3.2 Implementacién de pilas mediante listas enlazadas Cr 4.4.1 Implementacién de colas mediante arreglos 4.4.2 Implementacién de colas mediante listas enlazadas Ejemplos de aplicacién 4.5.1 Evaluacién de la parentizacién de expresiones 4.5.2. Notacién de expresiones prefija y postfija 4.5.3 Buisqueda de infinitivos en un texto Consideraciones generales Conclusiones .............00055 Tipos de datos abstractos dinémicos no lineales: 4rboles 193 Introducci6n . oo 193 Conceptos y definiciones .............. -194 5.2.1 Arboles perfectamente balanceados -200 Arboles binarios ordenados segiin el recorrido . 5.3.1 Arboles de expresion . . Arboles de biisqueda binarios . 5.4.1 Concepto y definiciones 5.4.2. Procedimientos sobre arboles binarios de busqueda... 0s... 209 5.4.3. Anélisis de la busqueda y de la insereién en Arboles binarios de busqueda .....0..0. 00.0000 cece ee eee eee Arboles de busqueda balanceados Soil Concept a a 5.5.2. Insercién en arboles AVL . Insercién de un nuevo nodo por la izquierda de un subérbol Insercién de un nuevo nodo por la derecha de un subérbol Algoritmo de insercién Ejemplos 5.5.3 Eliminacién en arboles AVL 5.5.4 Anélisis de arboles AVL ..... Arboles con varias condiciones mutuamente excluyentes Conclusiones ye viii 6 INDICE GENERAL 6.1 6.2 6.3 6.4 6. a =. 72 73 1S Arboles avanzados 245 Introduccion Arboles B . . 6.2.1 Btisqueda . 6.2.2. Insercién .. Ejemplo de insercin en un érbol B 6.2.3 Eliminacion . Arboles B binarios Arboles B binarios simétricos (BBS) . 64.1 Ejemplos de crecimiento de érboles BBS Conclusiones Programaci6n orientada a objetos 267 Introduccién . . Clases y objetos . Herencia y paso de mensajes ... Enlace dindmico y Polimorfismo Conclusiones Bibliografia 275 Indice analitico 277 F El objetivo basico de este texto es establecer los principios esenciales de los fundamentos de la disciplina conocida como Estructuras de Datos y Algoritmos. Dentro de las recomendaciones dadas por las asociaciones internacionales de reco- nocido prestigio, tales como IEEE y ACM, sobre curriculum en Informatica, consti- tuye por sf misma una de las nueve 4reas de interés: Arquitectura, Inteligencia artificial y rob6tica, Bases de datos y recuperacién de informacién, Comunicacién hombre-méquina, Célculo numérico y simbélico, Sistemas operativos, lenguajes de programacién, metodologia e ingenieria del software y Algoritmos y Estructuras de Datos. El término Informatica se empleard aqui para hacer referencia a la ciencia dedi- cada al estudio del tratamiento sistematico de la informacién, entendida ésta como una secuencia de caracteres de un alfabeto dado. En latinoamérica esta mas exten- dido el término computaci6n y en este texto deben entenderse como sindnimos. En general se engloba bajo el término Algoritmos y Estructuras de Datos el estudio de los algoritmos y su utilizaci6n en la resolucién de problemas, incluido el anélisis de problemas, el disefio de algoritmos y su implementaci6n, evaluacién y verificaci6n. El término Estructuras de Datos hace referencia a métodos de organi- zar, almacenar, ordenar y buscar cantidades significativas de datos. Evidentemente a amplitud de los contenidos que se incluyen en este érea, asf como su profundidad, es enorme. Por otro lado los conceptos, las técnicas y las bases fundamentales que consti- tuyen esta disciplina estén claramente establecidos desde principios de la década de los 70, y evidentemente existe un gran nimero de excelentes textos que los presen- tan. Sin embargo, este texto se ha disefiado con el fin de ser utilizado como texto base de la asignatura "Estructuras de Datos y Algoritmos” que se imparte en las titu- laciones de Ingenierfa Técnica en Informética de Sistemas e Ingenierfa Técnica en Informatica de Gestién, de la Escuela Universitaria de Informatica de la Universidad Nacional de Educacién a Distancia. Por ello la vocacién de este texto es primordial- x PROLOGO. mente pedagégica, desarrollandose con el fin de facilitar el estudio y el autoaprendi- zaje. De este modo todos los conceptos, algoritmos, tipos de datos abstractos, et se presentan ilustrados con ejemplos. Dichos ejemplos son descritos paso a paso y con detalle, con el fin de minimizar el esfuerzo de comprensién. En el mismo sentido los contenidos se han estructurado de manera que sean evaluables, separando lo fundamental de lo accesorio, lo formativo de lo informa- tivo. Asi por ejemplo, los algoritmos de clasificacién se presentan de manera que los detalles de implementaci6n, que requieren un esfuerzo especial ya que los procedi- mientos pueden ser relativamente largos, no interfieran con los conceptos basicos que definen el algoritmo. El hecho de presentar las implementaciones completa- mente desarrolladas responde a la necesidad, que todos tenemos, de disponer del "programa" final para comprobar su "funcionamiento". En cualquier caso lo funda- mental, tal y como se insiste a lo largo de todo el texto, son las ideas bésicas y los algoritmos, no los programas. Por ello, y con el fin de que el alumno no "pierda el tiempo" en escribir los programas, se incluyen en CDROM las fuentes tanto en Pas- cal como en Modula. Esto no quiere decir que sdlo los conocedores de estos lengua- jes de alto nivel pueden comprender este texto. De hecho todos los contenidos del mismo se presentan insistiendo claramente en la diferencia entre algoritmo y pro- grama, Tipo de Datos Abstracto y su implementacién. Por tanto, los conceptos bisi- cos son generales e independientes de las implementaciones utilizadas asi como del lenguaje utilizado para realizarlas. Los Autores. Madrid, Junio de 2000. CaPiTULO 1 Introduccion y conceptos fundamentales 14 ESTRUCTURAS DE DATOS En general puede entenderse que todo sistema informatico puede realizar dos tareas bisicas: célculos © gestién de informacién. Deliberadamente se ha prescin- dido de la expresion tratamiento de informacién por ser un aspecto més general que incluye al célculo como caso particular. En una tarea de cAlculo, funcidn que explica el término de origen anglosajén computador (computer), el objetivo fundamental seré la resoluci6n de problemas numéricos tal que a partir de un conjunto de datos dados se obtengan los resultados requeridos; mientras que en la tarea de gestién de informacién, descrita por el vocablo que procede del francés ordenador (ordenateur) se almacenan datos con el fin de organizarlos y recuperarlos cuando sean precisos. Dependiendo del 4mbito espectfico de aplicacién, se utilizar4 predominante- mente una u otra capacidad, o ambas. Asf por ejemplo, el célculo predomina en la actividad cientifica y técnica de manera que el computador se ha convertido en una herramienta habitual en cualquier centro de investigacién y desarrollo. Por otro lado, el tratamiento de informacin prevalece en las aplicaciones de gestién mediante las cuales los sistemas informaticos han irrumpido en la sociedad desde hace algunos afios, aplicdndose a labores que van desde la elaboracién del censo hasta el inventario de un pequefio comercio. Mas recientemente, el computador = INTRODUCCION Y CONCEPTOS FUNDAMENTALES forma parte de la vida cotidiana para un sinfin de tareas personales, desde la con- sulta de enciclopedias multimedia a la comunicacién telemética a través de Internet. En cualquier caso, independientemente de la tarea especffica a la que vaya a ser dedicado un sistema informatico, siempre se va a tener la necesidad de almacenar y manipular datos. Para ello se realizaran programas, es decir, una secuencia de ins- trucciones que indica las acciones que han de ser ejecutadas por el sistema progra- mable. La metodologia de disefio de un programa ha ido evolucionando a lo largo de los afios. En un principio era de hecho un arte, en el que la habilidad del programa- dor para utilizar las posibilidades que Je ofrecfan los primeros lenguajes de progra- macién era una componente fundamental. Ademés, el cédigo de un programa medianamente complejo solfa ser laborioso y dificil de seguir debido a que la ‘herramienta’ coménmente utilizada era la conocida sentencia ‘go to’, que obligaba a una planificacién de acciones ciertamente intrincada. Desde entonces el arte de programar ha ido conceptualizdndose, desarrollando técnicas para una programa- cién sistematica y bien organizada. Asi surgi la programacién estructurada en la que las tareas se dividen y agrupan en funciones o procedimientos de manera que por un lado se atiende a los detalles de programacién de éstos y posteriormente se utilizan en el programa principal que los requiera. La programacién estructurada, también llamada programacién orientada a pro- cedimientos, es bien conocida en la actualidad por todo aquel que se haya iniciado en programacién con cualquier lenguaje de alto nivel, y constituye un claro ejemplo de abstraccién. Los detalles de una tarea especifica se encuentran en una funcién que posteriormente ser vista como algo que tiene unas entradas y ofrece unas sali- das determinadas. De este modo, puede observarse que la abstraccién permite una programacién més sencilla y sistemdtica, siendo la operacién subyacente a todos los conceptos que serdn presentados a lo largo del texto. En sentido estricto, abstraer es la operacién mediante la cual la inteligencia llega a formar conocimiento conceptual comin a un conjunto de entidades, sepi rando de ellos los datos contingentes e individuales para atender a lo que los cons tuye esencialmente. Es decir; aislar mentalmente 0 considerar por separado las cualidades de un objeto. En general, cuando un estudiante de cualquier disciplina, escucha que debe abstraer unos conocimientos dados, suele pensar que es una tarea dificil, poco tangible y nada practica. Esto suele ser debido a que se confunde con ‘imaginar algo inexistente’. Abstraer debe entenderse como ‘extraer y agrupar’, es decir, descubrir las cualidades comunes y englobarlas bajo un mismo concepto. Esta capacidad de la mente se pone de manifiesto constantemente en la vida cotidiana; de hecho, el lenguaje es el exponente maximo de la abstraccién. En la programacién, la accién de abstraer se realiza constantemente y a todos los niveles. Incluso cuando se trata con ceros y unos se estdn ignorando las caracteristicas propias de cada uno, tales como los valores reales de las tensiones que los representan internamente en la maquina y su nivel de ruido. 1.2 ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 3 Atendiendo a estas consideraciones la metodologfa de programacién ha ido avanzando en el proceso de abstraccién. En la programacién orientada a procedi- mientos este hecho es claramente reflejado por la expresion del profesor N. Wirth: Estructuras de datos + Algoritmos = Programas ‘A lo largo de este capitulo serén analizados los conceptos fundamentales de las, dos columnas basicas en las que se basa la programaci6n: las estructuras de datos y los algoritmos. Ambos estén intimamente relacionados, hecho que se manifestaré a lo largo de todo el texto. Finalmente debe destacarse el hecho de que en el tiltimo nivel de abstra aparece una nueva metodologia conocida como programacién orientada a objetos, la cual, parafraseando la expresidn del profesor N. Wirth, podria expresarse como: Tipos de datos abstractos U Algoritmos = Objeto A esta metodologifa se dedica el tiltimo capitulo a modo de introducci6n. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 1.2.4 CONCEPTO Aunque los conceptos englobados en Ios términos ‘estructuras de datos’ y ‘tipos de datos abstractos’ son sencillos, en ocasiones puede producirse cierta con- fusién debido a que en algunos textos puede encontrarse el término ‘estructuras de datos’ referido a lo que en otros son los ‘tipos de datos abstractos’, y en gran ntimero de ellos se utilizan los términos ‘tipo de datos’ y ‘tipo de datos abstracto’ indistintamente. Con el fin de precisar los términos, en principio se distinguird entre ‘tipo’, ‘tipo de datos abstracto’ y ‘estructura de datos’. Definicién 1.1: Un tipo de datos es una coleccién de valores. Definicién 1.2: Un Tipo de Datos Abstracto (TDA) es un tipo de datos definido de forma tinica mediante un tipo y un conjunto dado de operaciones definidas sobre el tipo. Definicién 1.3: Una estructura de datos es la implementacién fisica de un tipo de datos abstracto. A la vista de estas definiciones cabe preguntarse qué son los enteros, caracte- res, etc., conocidos en programacién basica y generalmente predefinidos en los len- guajes de alto nivel. Por ejemplo, el tipo Booleano esta formado por los dos valores 4 INTRODUCCION Y CONCEPTOS FUNDAMENTALES True y False pero no es un tipo de datos abstracto ya que sobre él no se han definido las operaciones para manipularlo. Sin embargo, el tipo Booleano junto con los ope- radores booleanos (AND, OR, NOT) constituye un tipo de datos abstracto. Del mismo modo los enteros son un tipo formado por el conjunto de valores denomina- dos por las matemdticas ‘enteros’. Este tipo junto con las operaciones definidas sobre ellos forman un tipo de datos abstractos. Es importante considerar estas definiciones y tenerlas en mente a lo largo de todo el texto, no olvidando nunca que las operaciones que manipulan los objetos estén incluidas en la especificaci6n de un tipo de datos abstracto y que no interviene ninguna consideracién sobre la implementacién. Esta es expresa y conscientemente ocultada, hecho que es conocido como encapsulacién de datos (Figura 1.1 a). El hecho de que se oculte la informacién no significa que sea inaccesible. Se trata de disponer tinicamente de lo necesario para realizar las operaciones, funciones de acceso y variables de entrada y salida. Esto se realiza una vez asegurado que la implementacién es correcta y adecuada. procedure insertar: begin Velocidad —> Posicién Figura 1.1 a) Encapsulacién de datos b) Motor. El encapsulado, consecuencia misma del proceso de abstracci6n, se utiliza en todos los dmbitos de la ciencia y de la ingenierfa. Por ejemplo, se utilizan diagramas de bloques caracterizados por las entradas y salidas de los sistemas fisicos. De este modo un motor puede representarse por la entrada proveniente del actuador de con- trol, y la salida (velocidad y/o posicién) tal y como se ilustra en la Figura 1.1.b, sin atender a los detalles fisicos del mismo (escobillas o no, inducido, eléctrico o de combustién, etc.). Del mismo modo, esta idea se utiliza en otros Ambitos de la informatica, como por ejemplo en la técnica de monitorizacién en el desarrollo de sistemas operativos. Los conocedores del C esténdar y de los primeros compiladores de este len- guaje recordardn que el tipo de datos abstracto Boolean no era un tipo predefinido, mientras que en Pascal por ejemplo si lo era. Pero de este hecho es un error deducir que el tipo de datos Boolean no existe en C estdndar. Lo cierto es que no esta imple- ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 5 mentado en los tipos basicos, hecho superable sencillamente definiendo un tipo con los valores True y False y asocidndole los operadores AND, OR y NOT. Otro ejem- plo caracteristico es el de los enteros. Como es bien sabido, todo computador pre- senta limitaciones para la representacidn de los nimeros enteros de manera que el rango de posibles valores que se adaptan a este tipo dependen del computador. En general la implementacién de un entero utiliza una palabra para su almacenamiento. Asi, en un IBM PC con palabras de 16 bits se utilizan dos bytes para almacenar cada entero, con lo que el rango de posibles valores va desde -32768 hasta +32767. Pero otras mAquinas ofrecen rangos diferentes. Los clasicos DEC VAX y los procesado- res de la familia i86 de Intel (a partir del 80386) utilizan 32 bits, por ejemplo. Es mas, en lenguaje C es posible implementar los enteros mediante diversas formas, aumentando o disminuyendo el rango de valores. Asi, si el entero mediante la decla- racién int esté representado por 2 bytes, con la declaracién long int se almacena en 4 bytes; si int almacena en 4 bytes, la declaraci6n short int los almacenard en 2 bytes. Es decir, las implementaciones de algo tan sencillo como son los enteros pue- den ser distintas. Pero lo que es importante resaltar es que el tipo de datos abstractos denominado ‘enteros’ es siempre el mismo. Si en un caso dado Ja implementacién con el rango de 2 bytes es insuficiente sera preciso cambiarla, pero esto no afecta al tipo de datos abstracto ni al uso que se haya hecho de él a lo largo del programa ela- borado. Lo mismo sucede con otras estructuras mas complejas que se presentardn en temas posteriores. Por ejemplo, supéngase que en un programa se utiliza una pila, y en su momento el disefiador decidio utilizar una implementacidn estatica mediante un arreglo de 100 elementos. Pasado el tiempo se observa que es necesario un tamafio mayor. En ese momento basta con atender a los detalles de la implementa- cién de la estructura, aumentando el ntimero de elementos del arreglo 0 cambiando a una pila implementada dindmicamente. Estas modificaciones no requieren un gran esfuerzo ya que el tipo de datos abstracto es el mismo, y por tanto, la pila y su fun- cionalidad siguen siendo las mismas. Los anteriores comentarios no implican que las implementaciones sean poco importantes 0 irrelevantes. De hecho son fundamentales y la eleccin de una u otra implementacién para un TDA dado deberd analizarse cuidadosamente. Lo impor- tante es entender la diferencia entre un TDA y su implementacidn, y considerar cada uno de ellos en su momento. De esta manera se facilita el proceso de disefio asi como sus posibles modificaciones y mejoras. Como puede observarse de las consideraciones anteriores, el término ‘estruc- tura de datos’ hace referencia, segtin la Definicién 1.3, a la implementacién del TDA. En este sentido podria entenderse que los numerosos textos titulados Estruc- turas de datos y algoritmos hacen referencia a implementaciones de TDA y a algo- ritmos. Sin embargo, al manejar cualquiera de ellos, inmediatamente se precisan los términos, introduciendo los conceptos de TDA y estableciendo su significado. El término ‘estructura de datos’ se reserva para las representaciones fisicas de los datos. Con todo Io dicho, la seleccién de un TDA para resolver un problema dado deberd realizarse analizando en primer lugar el problema para determinar las restric 6 INTRODUCCION Y CONCEPTOS FUNDAMENTALES, ciones y especificaciones que debe satisfacer la solucién, seguidamente se deberan determinar las operaciones basicas a realizar y por ltimo se seleccionard la més adecuada. Evidentemente la mds adecuada vendré dada en funcién de alguna carac- teristica relevante, para lo cual habri que establecer algdn pardmetro objetivo que proporcione una medida de su coste o de sus beneficios. A lo largo de todo el texto se presentarén numerosos TDA, y una vez comprendidos tanto su concepto como su funcionalidad, serén analizados con detalle. Desgraciadamente no existe un tinico TDA capaz de ser el mejor en todos los casos, y todos ellos presentan inconvenientes y ventajas que los hacen adecuados 0 no para resolver un problema especffico. Asi por ejemplo, se presentarén los arboles de busqueda. Una vez analizados se obtiene la conclusién de que en el peor de los casos degenerardn en una lista lineal, perdiendo sus ventajas y haciendo que la biis- queda sea muy costosa. Buscando una solucién mejor se introducen los drboles AVL, se analizan y se concluye que en el peor de los casos la operacién de biisqueda tiene un coste menor. Sin embargo, esto no significa que sean los mejores; en una aplicacién dada es posible que nunca se dé el peor de los casos y por tanto, puede que los drboles de busqueda sean una mejor solucién para ese problema en concreto. El coste del TDA no viene determinado por un tinico factor sino que deberd ser analizado desde diversos puntos de vista. En general deberdn considerarse siempre dos aspectos. El primero, en relacién con el almacenamiento que seré establecido por los datos y la cantidad de ellos que deberdn ser manejados. El segundo aspecto, igualmente importante, serd el coste de las operaciones basicas. En el caso de los Arboles, por ejemplo, serdn los costes de las operaciones de insercién, busqueda y eliminacién. En general estas operaciones se realizan mediante algoritmos, con lo que su andlisis se realizaré utilizando las técnicas de anilisis de algoritmos. Como puede observarse, estos dos aspectos consideran las dos restricciones fundamentales que deben tenerse en cuenta en el disefio de todo programa: las limitaciones en el espacio de almacenamiento y el tiempo de ejecucin necesario para realizar una tarea. En definitiva, debido al proceso de abstraccién, el disefio deberé realizarse siguiendo tres pasos fundamentals: 1. Anilisis de datos y operaciones. 2. Eleccién del Tipo de Datos Abstracto. 3. Eleccién de la implementacién. En los capitulos siguientes se presentardn diversos TDA bésicos y bien conoci- dos. En todos ellos se presentard el concepto que incorporan, su utilidad y su coste. Sin embargo, no s6lo son interesantes con el fin de conocerlos para utilizarlos si fuese necesario, sino que fundamentalmente son utiles como ejemplo de metodolo- gfa de disefio de TDA. De este modo, si para un problema especifico no es stil nin- guno de los TDA basicos, se podré definir y realizar un TDA siguiendo la misma metodologia. Para finalizar esta seccién un breve comentario sobre terminologfa. En la mayorfa de la literatura se muestra una diferencia entre los términos ‘tipo de datos’ 1.2.2 ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 7 y ‘tipo de datos abstracto’ [Shaffer, 1997], [Heileman, 1998]. Cuando esto sucede, el concepto de TDA sigue siendo el dado en la Definicién 1.3 mientras que se hace referencia a ‘tipo de datos’ como una descripcién matematica y formal de un tipo y un conjunto de operaciones. En otros textos [Dale, 1989] se utiliza el término ‘tipo de datos’ como TDA. En cualquier caso, desde el punto de vista de la metodologia de programacién el concepto fundamental que debe considerarse siempre y com- prender sin ambigiiedades es el de TDA. Con el fin de tener una perspectiva de conjunto, en el siguiente apartado se rea- liza una breve presentacién de los tipos de datos conocidos de programacién bisica, pero presentados como TDA. TIPOS DE DATOS BASICOS En un primer acercamiento a la programacién, independientemente del len- guaje utilizado, es habitual entender que los tipos de datos son herramientas 0 utili- dades para almacenar los datos necesarios para resolver el problema. Asf, se suele entender que los enteros se almacenan en variables tipo Entero (int en C, Integer en Pascal 0 Modula2, ...) , los caracteres en variables tipo cardcter (char en C, en Pascal o Modula2....). Es decir, en este contexto no suele atenderse a la diferencia entre tipo y TDA. Sin embargo, todos ellos son de hecho TDA. De este modo las definiciones de los tipos de datos estandar son las siguientes: Definicién 1.4: El TDA Entero tiene como tipo el conjunto de ntimeros enteros definido por las matematicas {-1, -2, ..., 0} U {0, 1, 2, ..., 2}, y como operacio- nes la suma, la resta, la multiplicacién y la divisién entera. Definicion 1.5: El TDA Real tiene como tipo el conjunto de nuimeros reales defi- y como operaciones la suma, la resta, la multiplicaci6n y la .6: EL TDA Booleano tiene como tipo el conjunto de valores booleanos {True, False) y como operaciones las definidas por el dlgebra de Boole (AND, OR, NOT). Definicién 1.7: El TDA Cardcter tiene como tipo el conjunto de caracteres definido por un alfabeto dado y como operaciones todos los operadores relacionales (<, >, =, 2, 1 <>). En el apartado anterior ya se realizaron algunos comentarios sobre la imple- mentacién de los TDA‘Entero y Booleano. Del mismo modo el TDA Real tiene en su implementacién diferentes soluciones, en funcién de la representacién que se realice de ellos, que depende de diversos factores. En coma flotante debe conside- rarse la representacién de la mantisa (complemento a 2, magnitud-signo,...), la del exponente (polarizado, no polarizado....), la localizacién de ambos, etc. Estas imple- mentaciones estan normalizadas. Por ejemplo, el Institute of Electrical and Electro- nics Engineers (IEEE) ha propuesto la norma IEEE 754-1985 para la representacién de ntimeros en coma flotante para las operaciones aritméticas en mini y microcom- Tabla 1.1 Tabla 1.2 INTRODUCCION Y CONCEPTOS FUNDAMENTALES. putadores, en la que se contemplan tres formatos basicos, denominados de simple, doble y cuddruple precisi6n (véase [Dormido, 2000]). Anélogamente el TDA Caricter se implementaré de diferentes formas depen- diendo del alfabeto utilizado. En general, todos los alfabetos vendran caracterizados por una secuencia de cotejo, es decir, por la secuencia ordenada de los caracteres que constituyen el conjunto. En todos los alfabetos, como es natural, las letras se encuentran ordenadas entre sf, al igual que los digitos. Asf'a'<'b'<'Cl.., y'I'<'2'< '3'. Los tres conjuntos de caracteres més conocidos son el CDC-Cientifico, el EBCDIC (Extended Binary Coded Decimal Interchange Code) y el ASCII (Ameri- can Standard Code for Information Interchange). Las Tablas 1.1, 1.2 y 1.3 mues- tran las secuencias de cotejo de los tres. Tabla de caracteres ASCII. El ntimero correspondiente de la secuencia de cotejo, se forma con dos cifras hexadecimales, siendo la primera cifra, la que aparece en la primera columna y la segunda la que aparece en la primera fila. E.B. indica el caracter espacio en blanco. 0 _JNUL [SOM] STX]ETX PT GE FF [CR 1 [ove [sea [eval 1c NL EM DuP| SF | FM [178 2 ETB[ESC ENQ : 3 SYN EOT| RA [NAK 4 [es é <[c[+ ae ths|[* [> = Golan laf TT. [%[_ [> [7 7 #[e =|" 8 a e[d tTsTryi 9 T[m[alfo air A ~[sitijujtviwt]xjy[z 8 of) [7 [Kt im[niolrialr Ef. Si /ata|aUs)avajaWalexe)avalez Flo[:+/2|[s/4[s/[e|7]/s|9 Tabla de caracteres EBCDIC. La celda con E.B. indica el espacio en blanco. Tabla 1.3 ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 9 Secuencia de cotejo CDC-Cientifico. La celda con E.B. indica el espacio en blanco. En estas tablas, las celdas con més de un cardcter indican caracteres de control que aparecen representados por su correspondiente mnemotécnico. Como puede observarse en el c6digo ASCII los ntimeros van antes que las letras, mientras que en los otros dos cédigos van después. Las mintisculas van antes que las maytisculas en EBCDIC, después en ASCII, y en CDC-Cientifico no forman parte del conjunto de valores. Los tipos de datos definidos hasta ahora se conocen como tipos de datos sim- ples 0 atémicos debido a que no son divisibles, es decir, no tienen componentes que puedan ser accedidos independientemente. Todos ellos excepto los reales son tipos ordenados, y a todos los tipos ordenados se les puede aplicar los operadores relacio- nales. En este contexto se definen los ‘tipos de datos escalares’ de la siguiente forma Definicién 1.8: Se denominan tipos de datos escalares a aquellos en los que el con- junto de valores est ordenado y cada valor es atémico. Ejemplos de ellos son los tipos de datos Cardcter, Entero, Real y Booleano. Son scalares ya que todos ellos son de tipo atémico y estan ordenados (los enteros y reales segtin indican las matematicas, los caracteres segtin su secuencia de cotejo y los booleanos tal que False es menor que True). Algunos tipos escalares presentan una propiedad adicional, la ordinalidad. Definicién 1.9: Se denominan tipos de datos ordinales a aquellos en los que cada valor tiene un tinico predecesor (excepto el primero), y un tinico sucesor (excepto el Ultimo). Los tipos Cardcter, Entero y Booleano son ordinales, pero como es bien cono- cido de matemiticas el tipo Real no lo es. Los lenguajes de alto nivel suelen presen- tar tres funciones adicionales asociadas a los tipos de datos ordinales: una que devuelve la posicién de un elemento (0rd), otra que devuelve el predecesor (Pred), y otra que devuelve el sucesor (Succ). Es bien sabido de la matematica, que los ntimeros reales no forman un conjunto ordenado al no ser numerable. Es bien cierto que a los ntimeros reales se les puede aplicar los operadores relacionales pero no se puede determinar su predecesor 0 su sucesor de forma tinica. Pensemos por ejemplo en los ntimeros 5.1 y 5.2; esté claro que 5.1<5.2 y podrfamos concluir erréneamente que 5.1 es el predecesor de 5.2 y este tiltimo el sucesor de 5.1. Sin embargo si consideramos dos cifras decimales, el 10 INTRODUCCION Y CONCEPTOS FUNDAMENTALES predecesor de 5.20 (=5.2) serd 5.19 y el sucesor del 5.10 (=5.1) seré el 5.11. Queda claro pues que para un ntimero real no se puede establecer un nico predecesor y un Gnico sucesor ya que estas operaciones dependen de la precisién con que se trabaje y no del nimero en si. Obsérvese que esto no afecta a los operadores relacionales y por tanto, se sigue cumpliendo que: 5.1=5.10<5.20=5.2. El problema viene porque entre cada par de nimeros reales que se escoja, siempre hay un ndmero infinito de ellos. En el contexto de la iniciacién a la programaci6n estructurada mediante cual- quier lenguaje de programacién, los tipos de datos definidos hasta ahora, suelen denominarse tipos de datos predefinidos 0 tipos primitivos estandar debido a que la mayoria de los lenguajes de alto nivel los incorporan en sus normas bdsicas. Sin embargo, debe observarse que incluso a este nivel inicidtico surge la necesidad de definir tipos para estructurar los datos adecuadamente. En este contexto suelen denominarse ‘tipos de datos definidos por el usuario’, siendo los caracteristicos de Ia metodologia de programacién estructurada los tipos: conjunto, arreglo y registro. Dado que son divisibles en componentes que pueden ser accedidas individualmente serdn tipos de datos compuestos. La mayoria de estos tipos de datos son colecciones de componentes organiza- das mediante la forma de acceso a cada una de las componentes individuales. A este tipo de datos se le denomina tipo de datos estructurado. En general, las operaciones asociadas a los tipos estructurados son las de alma- cenar y recuperar sus componentes individuales. Cuando todos los elementos de la colecci6n son de un mismo tipo, denominado tipo base, se dice que el tipo es homo- géneo mientras que cuando no lo son se dice que es heterogéneo. Las siguientes definiciones precisan los TDA compuestos basicos. Definicién 1.10: El TDA Conjunto es una coleccién de elementos tratados con las operaciones uni6n, interseccién y diferencia de conjuntos. Definicién 1.11: EL TDA Arreglo es una coleccién homogénea de longitud fija tal que cada una de sus componentes pueden ser accedidas individualmente mediante uno (unidimensional) o varios (multidimensional) indices, que serén de tipo ordinal, y que indican la posicién de la componente dentro de la coleccién. Definicién 1.12: El TDA Registro es un tipo de datos heterogéneo compuesto por un niimero fijo de componentes denominadas campos a las que se accede mediante un selector de campo (expresién formada por el nombre y un operador de seleccién como por ejemplo: ‘.’). Como puede verse el TDA Conjunto no es estructurado ya que no est4 organi- zado mediante el modo de acceso a sus componentes individuales, mientras que el Arreglo y el Registro si lo son. Es importante observar el anidamiento existente entre los TDA. Los registros pueden tener como campos tipos de datos simples arreglos o incluso otros registros. Cada uno de los campos seré tratado como indica la definicién del TDA al que pertenecen. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS abl Los TDA bisicos suelen ser los més frecuentemente utilizados, pero ademés cada problema puede requerir la definicidn de varios TDA propios. Asf por ejemplo, en un problema matemitico puede definirse un TDA matriz de la siguiente forma: Definicién 1.13: El TDA matriz se define como aquel que tiene como tipo el con- junto de matrices definido por las matematicas (disposiciones rectangulares de ele- mentos organizados en filas y columnas), y los operadores asociados a las mismas: Obtener_elemento (mediante la indexaci6n por fila y columna), Asignar_elemento, Sumar, Restar, Negar, Producto_escalar, Producto_matricial, Determinante, Inversa y Transponer. ‘A lo largo de este texto se irdn presentando los TDA mis utilizados en las apli- caciones informaticas. Todos ellos vendrén dados por la necesidad de organizar y recuperar la informacién almacenada. Ejemplo basico de ello es el TDA lista, defi- nido de la siguiente forma: Definicién 1.14: El TDA lista (o Secuencia) es una coleccién homogénea de datos, ordenados segtin su posicién en ella, tal que cada elemento tiene un predecesor (excepto el primero) y un sucesor (excepto el tiltimo), y los operadores asociados sobre ellas s + Insertar: inserta un elemento, x, en una posicidn p, de la lista, pasando los ele- mentos de la posicion p y siguientes a la posicién inmediatamente posterior. * Localizar: localiza la posicién p en la que se encuentra un elemento dado x * Recuperar: encuentra el elemento x que est en la posici6n p. * Suprimir: elimina de la lista el elemento de la posicién p. * Suprimir_dato: elimina de la lista cualquier aparici6n del elemento x. * Anula: ocasiona que la lista se vacie. + Primero (Fin): proporciona el primer (tiltimo) elemento de la lista «= Imprimir: imprime todos los elementos de la lista en su orden. Obsérvese que algunos de estos operadores basicos se podrian realizar utili- zando un subconjunto del resto de operadores. Asf por ejemplo, Suprimir_dato podria realizarse con el operador Localizar, que proporciona la posicién p en la que se encuentra un elemento dado x y seguidamente con Suprimir, que elimina de la lista el elemento de la posicién p. Sin embargo, se incorpora a los operadores aso- ciados dada su frecuencia de utilizacién y debido a que su implementacién particu- larizada mejorar el coste de la misma. Esta estrategia no es nueva, recuérdese que los Enteros tienen definido el operador multiplicacién, pese a que podria ser reali- zado por iteracin del operador suma. Sin embargo la multiplicacién es una op: cién muy frecuente y existen implementaciones especificas que mejoran la suma iterada. En general el término ‘lista’ se utiliza cuando el TDA se implementa sobre memoria principal mientras que ‘secuencia’ suele reservarse para implementaciones sobre memoria secundaria. Evidentemente, segtin su implementacién, las operacio- nes bdsicas asociadas serdn de una forma u otra. 12 INTRODUCCION Y CONCEPTOS FUNDAMENTALES. 1.2.3 Como puede observarse, la lista es una estructura dindmica desde el punto de vista légico, ya que su longitud dependera del ntimero de elementos que tenga, aumentard al insertar y se reduciré al suprimir. El TDA lista puede implementarse de formas muy diferentes. La més inme- diata a partir de los TDA presentados hasta ahora es mediante arreglos. As‘, la lista, que es din4mica independientemente de su implementaci6n, se realiza mediante una implementacién estatica. Sin embargo también es posible implementarla dinémica- mente, mediante TDA basados en punteros. En general, los tipos de datos presentados hasta ahora, tanto simples como compuestos, son bien conocidos por aquellos iniciados en las técnicas bisicas de programacién. No ocurre lo mismo con otros dos TDA fundamentales: la Secuencia y los Punteros. El primero de ellos debido a que como claro ejemplo de abstraccién suele confundirse con alguna de sus implementaciones (ficheros o archivos, buffers de memoria, ...), mientras que el segundo suele estar poco dominado por conside- rarse un aspecto ‘avanzado’ de programacién bisica. Por ello se tratan de forma algo més detallada en las siguientes secciones. TIPOS DE DATOS ABSTRACTOS: PUNTERO Y LISTAS ENLAZADAS En principio los punteros son materia conocida de las nociones bisicas de pro- gramacién. En esta seccién se recuerdan los conceptos esenciales de los mismos dado que su manejo ser4 fundamental para todas las estructuras de datos dinémicas presentadas en el texto. En principio un puntero es un tipo de datos simple cuyo valor es la direccién de una variable de otro tipo, denominada variable referenciada. La Figura 1.2 muestra la representaci6n gréfica caracteristica de estos tipos. Variable puntero Variable referenciada Cualquier tipo de Datos Figura 1.2 Concepto de punteros y variables referenciadas. La utilidad de estos tipos radica en que permiten realizar una reserva dindmica de memoria. Para comprender este concepto es importante recordar cémo trabaja un programa compilado. Recuérdese que en cualquier programa de alto nivel lo pri- mero que debe realizarse es la declaracién de constantes (Const), tipos (Type) y variables (var) que el programa va a necesitar. Cuando se ejecuta el programa lo pri- mero que se hace es reservar memoria para todas estas variables, El sistema opera- tivo es quien se encarga de gestionar la memoria primaria, y lleva el control de la memoria que esté reservada porque es necesaria para los programas que se estén ejecutando y 1a que el sistema tiene libre. A estas variables se las denomina varia- ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 13 bles estdticas, ya que ‘existirn’, en el sentido de que disponen de memoria reser- vada, a lo largo de toda la ejecucién del programa. Las variables referenciadas son variables dindmicas, es decir, se crean en tiempo de ejecucion. Recuérdese que ‘crear’ una variable significa reservar espacio en memoria para dicha variable y asignar una etiqueta a ese espacio, es decir, tomar la memoria libre del sistema necesaria e indicar que esté ocupada por dicha variable. Para las variables estéticas, esta indicacién se realiza en la seccién de declaraciones de forma que en tiempo de ejecucién la memoria estd reservada siempre, se utilice o no. Sin embargo, la memoria requerida por las variables dinémicas se reserva, como memoria ocupada, durante la ejecucién del programa y s6lo cuando es necesaria. Cuando no hace falta se libera 0 ‘destruye’, es decir, se indica que es memoria libre y el sistema podrd reutilizarla para otras necesidades. En la mayorfa de los computadores el valor de un puntero es un ntimero entero, debido a que las posiciones de memoria van desde cero hasta el tamafio de la memo- ria menos uno. Sin embargo, este valor no es de tipo entero sino una direccién. Es més, en algunos tipos de maquinas, la memoria es accedida a través de paginas o segmentos y la direccién puede tener una estructura compleja formada por un selec- tor 0 indicador de segmento y un desplazamiento dentro del segmento, alejéndose considerablemente del concepto de tipo entero. El contenido de Ja variable referen- ciada puede ser cualquier tipo de dato: registro, otro puntero, etc. (Figura 1.2). La declaracién de los tipos puntero se realiza en la seccién TYPE, En Modula2, por ejemplo, la sintaxis es la siguiente: TYPE Tipo_puntero = POINTER TO Tipo_variable_referenciada; donde Tipo_variable_referenciada es el tipo de datos al que pertenecerdn las varia- bles referenciadas. La declaracion de la variable puntero se realiza en Ja seccién VAR, y su sintaxis en Modula? es: VAR variable_puntero : Tipo_puntero; La variable referenciada es accedida con el puntero mediante el operador apun- tador, cuyo simbolo en Modula? es el acento circunflejo: **” Contio ya se ha explicado detalladamente, la memoria necesaria para la variable puntero es reservada y ocupada de la misma forma que las variables estaticas. Sin embargo, la variable referenciada (por ejemplo un registro con varios campos) no existe hasta que no ha sido creada. Para crearla en Modula? se dispone del procedi- miento Allocate, cuya sintaxis es: Allocate (variable_puntero, SIZH(Tipo_variable_referenciada) }; 14 INTRODUCCION Y CONCEPTOS FUNDAMENTALES Este procedimiento realiza dos acciones. En primer lugar toma la memoria libre necesaria para la variable referenciada. Esto lo realiza mediante la funci6n stzz que determina el tamafio de la variable referenciada con el fin de reservar tinica- mente la cantidad de memoria imprescindible. En segundo lugar asigna la direccin de memoria que ha reservado al puntero, variable_puntero. Tras este procedimiento Ia variable referenciada existe en el sentido de que hay memoria asignada para ella y ademés puede ser accedida por el puntero. Una vez que una variable referenciada ya no va a ser utilizada por el programa, sera destruida o liberada. El procedimiento en Modula2 que realiza esta tarea es Deallocate, cuya sintaxis es: Deallocate(variable_puntero, SIZE(Tipo_referenciada) } ; P 1 : |e} . 2| pe MODULE ejemplo; 2 : | ‘TYPE al puntero = POINTER TO integer; a VAR i P,@ : puntero; ~ Plt 8 |p 3) BEGIN : a ke 2 ALLOCATE (p, SIZE (int : [.] A gt (p, SIZE (integer) } le I Pp (4) 3 ale] 4 Ply 5} p*, a 5 (s) ale 6 —_DEALLOCATE(p, SIZE (integer) } END. : |e 6) ¥ g [27 Figura 1.3 Ejemplo de programa mostrando las operaciones bésicas con punteros. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 15 Los comentarios anteriores muestran las caracteristicas del tipo puntero, pero para poder establecerlo como TDA es imprescindible analizar las operaciones aso- ciadas a los mismos. Estas son la asignacién y la comparacién. Recuérdese que los valores de los punteros son las direcciones a las que apun- tan y por tanto, estas operaciones afectan a dichas direcciones. La Figura 1.3 ilustra estas operaciones y las anteriores consideraciones. En primer lugar se declara un tipo puntero a entero, de manera que la variable referenciada sera de tipo entero. Seguidamente se declaran dos variables puntero de este tipo, p y ¢. Con ello el valor de estas variables no se asigna de ninguna manera, por lo que su contenido debe considerarse desconocido. En este sentido su comportamiento es el mismo que cual- quier otra variable estatica. Cuando durante la ejecucién del programa se requiera utilizar las variables referenciadas, éstas se crean mediante las sentencias: Allocate (p,SIZE(integer)) y Allocate(q,SIZE(integer)) (0 también: New(p) y New(q)). Entonces cada puntero tendra como valor la direccién de su variable referenciada de forma que apunta hacia ella. En esta situacion las variables referenciadas recién creadas no tienen nin- gtin valor (estan sin inicializar). Para asignarlo se accede a la variable referenciada mediante el nombre del puntero que la apunta y el operador de acceso ‘*’, realizén- dose la asignacién mediante su operador, ‘:=’. Debe resaltarse el hecho de que esta asignacién no es la operacién asociada al TDA puntero, sino que es simplemente la asignacién de valores a variables, El hecho de que éstas sean variables referenciadas no implica diferencia alguna. En la Figura 1.3 se muestra la asignacién del valor 8 a la variable referenciada (p*:=8). pl of pe pie Pp’ Figura 1.4 Pérdida de memoria debido a una incorrecta asignacién entre punteros. La asignacién de punteros consiste en la asignacién de valores puntero, es decir direcciones, entre variables puntero. Asi q:=p tiene como resultado que el valor de q sea la direccién almacenada en p, es decir, q apunta a donde apunta p. Debe tenerse en cuenta que la asignacién incorrecta de punteros puede tener un efecto muy nega- tivo. Este efecto consiste en dejar una variable refenciada sin tener acceso a ella, tal y como se ilustra en la asignacién de punteros de la Figura 1.4. Obsérvese cémo la variable que estaba apuntada por q queda sin apuntar por nadie (sefialada con un cfr- culo punteado en la Figura 1.4). Por tanto, se est ocupando memoria que no podré ser reutilizada. Por ello, antes de asignar punteros debe tenerse en cuenta que si la 16 INTRODUCCION Y CONCEPTOS FUNDAMENTALES variable referenciada va a ser necesitada posteriormente tiene que estar apuntada por algin puntero, y si no lo va a ser entonces debe ser liberada, es decir, debe ser devuelta a la memoria libre del sistema. Esto se realiza en Modula2 mediante los procedimientos Deallocate 0 Dispose. Del mismo mode, la asignaci6n entre variables referenciadas no es més que una asignacién entre variables del tipo de la misma. Asf, segtin se muestra en la Figura 1.5, la asignacién q*:=p", asignaria el valor de p* (25), a q*, en el supuesto de que se hubiesen creado las correspondientes variables referenciadas. of . = : a 1 25 | 25 Figura 1.5 Asignacién entre variables referenciadas. La segunda operacién asociada a los punteros es la comparacién, Al comparar se est4 comprobando si sus direcciones son iguales 0 no, es decir, si apuntan 0 no a la misma direccién de memoria. En la Figura 1.6 se muestra cmo cuando apuntan a diferentes direcciones el resultado de la comparacién es Falso (aunque los conteni- dos de las variables referenciadas sean idénticos), mientras que es Verdadero si apuntan a la misma direccién. p [*}—>}25 p [+> ale 25 ale es TRUE es TRUE p=q eS FALSE p=g @8 TRUE Figura 1.6 Operaciones de comparacién entre punteros y variables referenciadas. Es importante determinar cudndo un puntero no sefiala a ninguna variable refe- renciada. Para ello, en Modula? por ejemplo, se dispone de la palabra clave NIL que representa una constante y en otros lenguajes se dispone de constantes similares. Asi, la asignaci6n de esta constante a un puntero indica que éste no apunta a nada. Su representacién gréfica se muestra en la Figura 1.7. Esta constante tiene la parti- cularidad de ser universal y poder ser asignada a cualquier tipo de puntero, indepen- dientemente del tipo de variable referenciada al que apunte. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 7 Ptr_carl puntero ptrecart Figura 1.7 1.2.4 Puntero que no apunta a ninguna variable referenciada. Atendiendo a estas consideraciones el TDA puntero puede definirse de la siguiente manera: Definicién 1.15: El TDA puntero es un tipo de datos simple cuyos valores son direcciones de memoria, y sus operadores asociados son la asignacién de punteros y la comparacién de punteros. Por tiltimo, debe tenerse en cuenta el ahorro de almacenamiento que supone la utilizacién de punteros. La reserva de memoria realizada estaticamente sélo afecta a las variables puntero mientras que las referenciadas se crean y se destruyen de manera que s6lo se reserva memoria cuando es necesitada. En este sentido, el ejem- plo de la Figura 1.3 no es en absoluto ilustrativo de este hecho, y debe considerarse un ejemplo académico con el tnico propésito de ilustrar de forma sencilla las opera- ciones basicas y los operadores asociados a este TDA. En efecto, obsérvese que estéticamente se reservan dos punteros, y si cada puntero requiere cuatro bytes (como sucede habitualmente en las méquinas de 32 bits), ocupan lo mismo que podrian requerir cuatro variables de tipo entero en una maquina que representa los enteros con 16 bits. Por tanto, al crear las variables referenciadas se estarian utili- zando un total de doce bytes, ocho reservados estdticamente para los punteros y cua- tro din4micamente para las variables referenciadas, cuando con reservar cuatro de forma estdtica serfa suficiente para almacenar los dos enteros deseados. Sin embargo el ahorro de memoria y su apropiada utilizacién es evidente cuando la memoria a utilizar por Ja variable referenciada es superior a la necesaria para alma- cenar un puntero, o una misma memoria debe ser utilizada para distintos fines a lo largo de la ejecucién de un programa; o se utiliza, como se va a describir en el siguiente apartado con las listas enlazadas, para la creacién de estructuras de datos dindmicas. Los punteros son la base de construccién de todas las denominadas estructuras dindmicas, como los drboles que se presentarén en este texto, o las listas enlazadas. Seguidamente se recuerdan los aspectos fundamentales de estas tiltimas LISTAS ENLAZADAS Para almacenar de una forma organizada un conjunto de datos homogéneos se dispone de los arreglos. Esta estructura, como se dijo, es estatica y esté incorporada en los lenguajes de alto nivel. En este apartado se presentan las listas enlazadas. Su finalidad, como en el caso de los arreglos, es almacenar organizadamente datos del mismo tipo. 18 Figura 1.8 INTRODUCCION Y CONCEPTOS FUNDAMENTALES : Datos Enlace| | Representacién esquematica de una lista enlazada y de uno cualquiera de sus nodos. El ‘campo destinado a almacenar la informacién (Datos) es normalmente de un tamafio mucho mayor que el campo enlace. Las listas enlazadas son tipos de datos dindmicos que se construyen con nodos. Un nodo es un registro con dos campos, uno de ellos contiene las componentes y se Je denominard ‘datos’ (o data) y el otro es un valor que sefiala al siguiente nodo y se le denominaré enlace (0 next) El campo datos debe entenderse conceptualmente, es decir, en una implementacién concreta pueden ser varios los campos que se conside- ran como datos. Por ejemplo, podrfan ser los campos: Nombre, Apellidos, Direc- cién, DNI, etc. La definicién del TDA lista enlazada es la siguiente: Definicién 1.16: El TDA lista enlazada es una coleccién de nodos ordenada segtin su posicién, tal que cada uno de ellos es accedido mediante el campo enlace del nodo anterior. La Figura 1.8 ilustra el concepto de lista enlazada. Haciendo uso de los punteros, es decir, definiendo los valores del campo Enlace del tipo nodo como punteros, las listas enlazadas se implementan aprovechando todas las ventajas de la asignaci6n dindmica de memoria. Esta es, de hecho, la forma habitual y mds eficaz de implementar la lista enlazada (Io que explica que la repre- sentaci6n grdfica de una lista enlazada se realice en términos de direccionamientos dinmicos, tal y como muestra la Figura 1.8). Sin embargo, ésta no es la unica implementacién posible. Obsérvese que las lis- tas enlazadas pueden implementarse estaticamente, sin més que definir el tipo del arreglo como nodos y utilizar los indices en el campo enlace para determinar el siguiente nodo. La Figura 1.9 muestra un ejemplo de este tipo de implementacin de lista enlazada. En esta figura, cada nodo esté almacenado en una posicién del arreglo y est4 formado por un registro con dos campos, al igual que la implementacién dindmica basada en punteros. Por una parte est el campo de datos que contiene la informa- cién almacenada en Ia lista, y por otra el campo enlace, con la diferencia de que ahora en lugar de almacenar un puntero, es un valor ordinal que apunta a la posicién del arreglo en la que esté el siguiente elemento. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 19 Figura 1.9 Implementacién estatica de una lista enlazada mediante un arreglo de registros. ‘Aunque en principio la gestin de una lista implementada mediante un arreglo pueda parecer més sencilla que una con punteros, no es cierto. Téngase en cuenta que en el caso de los arreglos siempre hay que mantener una lista enlazada con los elementos vacios, de forma que cuando sea necesario aiiadir un nuevo elemento, se tome de la lista de nodos disponibles y se affada a la lista. Y a la inversa, cuando haya que eliminar un nodo de Ja lista habré que devolverlo a la lista de disponibles, con lo que el trabajo es siempre el doble, puesto que hay que mantener dos listas sobre el mismo arreglo. En el caso de la lista con punteros, esta tarea la realiza el sistema automdticamente. En este punto hay que marcar la distincién entre un tipo de datos abstracto y la naturaleza de su implementacién. Ambos conceptos pueden ser considerados de forma estética o dindmica. Una variable de tipo ‘array’ (arreglo) es una estructura tipicamente estatica, pero puede almacenarse en memoria de forma estética (decla- rada en una zona de declaracién de variables) 0 de forma dindémica (mediante un puntero). Lo mismo sucede, por ejemplo, con una pila 0 una lista, que son por natu- raleza estructuras tipicamente dindmicas pero que pueden implementarse con asi nacién de memoria estética (dentro de un array) o con asignacién de memoria dindmica (basada en punteros). La Figura 1.10 muestra varios ejemplos con Jas cua- tro posibilidades segtin se combinen estructuras de datos estaticas o dindmicas con asignacién de memoria estatica o dinémica. TOA Estaticas Dindmicas g 8 integer pilas, colas, 5 S| recon ae 2 a ray con arrays 8 8 sg Ainteger pilas, colas, 8 E Areal lista, arboles, & S| *record etc. <2 array ‘con punteros Figura 1.10 Ejemplos de tipos de datos y de sus posibles implementaciones. 20 INTRODUCCION Y CONCEPTOS FUNDAMENTALES, Comparando las definiciones de los TDA Lista y Lista enlazada es evidente que una forma natural de implementar una Lista en memoria primaria es mediante una Lista enlazada, y asf se hace habitualmente. Sin embargo, esto no debe llevar a con- fundir ambos ‘conceptos. El TDA Lista puede implementarse perfectamente mediante arreglos. De hecho, en antiguos lenguajes de programacién, tales como Algol o el antiguo FORTRAN, no se disponfa de implementaciones para punteros, hecho que no impedia que se implementasen listas (mediante cursores, véase deta- les en [Aho, 1988], por ejemplo). A a vista de estas consideraciones es importante reflexionar sobre las caracte- risticas de los TDA Arreglo, Lista enlazada y Lista. Obsérvese en primer lugar que los arreglos y las listas tienen como tipo componente cualquiera, mientras que las listas enlazadas tienen como componentes nodos. Los arreglos son estructuras esté- ticas, mientras que las otras dos son dindmicas. El arreglo accede a sus elementos, de forma aleatoria, mediante una indexacién de los mismos, mientras que la lista y Ja lista enlazada lo realizan secuencialmente; y la lista enlazada necesariamente mediante el campo Enlace. La Figura 1.11 muestra una comparativa de las caracte- risticas de estos TDA. Tipo de datos Aleatorio Cualquiera Secuencial Cualquiera Lista enlazada Secuencial Nodos Figura 1.14 Comparativa de los TDA Arreglo, Lista y Lista enlazada. Seguidamente se presenta la implementacién dindmica de la lista enlazada. Como se ha dicho, las variables dindmicas pueden crearse y liberarse durante la eje- cuci6n del programa. Haciendo uso de las variables dinémicas podran construirse estructuras de datos con un mimero de elementos que varia durante la ejecucién del programa. El campo de enlace ser4 un puntero y los nodos son variables referenciadas. Con esto, la declaracién de tipos para los nodos en Modula? es: TYPE Ptr_Nodo = POINTER T0 Nodo; Nodo = RECORD datos : Tipo_datos enlace : Ptr_Nodo; END; ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 21 Como se ha dicho, una lista enlazada es un conjunto organizado de componen- tes en los que el orden se establece mediante el campo enlace de cada nodo. Para acceder a la lista se tiene un puntero al primer nodo que se denomina puntero externo. La declaracién de la lista se realizard mediante la del puntero externo, que por economia del lenguaje se le suele denominar ‘lista’. En Modula? seria: VAR lista : Ptr_Nodo; Para ganar claridad, también puede definirse un nuevo tipo Tlista y declarar las variables de este nuevo tipo: TYPE Tlista = Ptr_Nodo; VAR lista : Tlista; En cualquier caso, sobre este TDA se puede realizar cualquier funcién necesa- ria gestionando adecuadamente los punteros. Seguidamente se presentan algunas de las funciones mas elementales. Insercién por la cabeza Al ser ésta la primera operacién se va a comentar detenidamente para ilustrar el manejo de punteros. Las siguientes operaciones se presentaran de forma resumida. Para insertar un nuevo elemento en la cabeza de una lista ya existente se deberd crear un nuevo nodo, seguidamente habré que introducir el nuevo dato a almacenar en el campo de datos y finalmente realizar los enlaces adecuados para recolocar los nodos en Ia lista, Es decir: 1. Crear el nuevo nodo (reservar memoria). 2. Almacenar el dato en el campo correspondiente (datos) 3. Como este nuevo nodo va a ser el primero, su campo enlace deberé apuntar al hasta ahora primer nodo. 4. Por iiltimo el enlace externo (lista), no perteneciente a ningtin nodo y que apunta al primer nodo de la lista, deberd apuntar ahora al nuevo nodo. El manejo de punteros correspondiente a esta secuencia de pasos se ilustra en la Figura 1.12. Los mimeros indican el orden en el que debe efectuarse cada enlace, y el nodo rodeado por un cfrculo punteado es el nuevo nodo. Obsérvese que el orden de las acciones es fundamental. Si primero se realizase la asignacién del puntero externo al nuevo nodo, cuando se desease enlazar este nuevo nodo con la lista no se podria, pues su direccién estaba en el puntero lista. La lista se ha perdido. La gestion de punteros debe realizarse de forma cuidadosa. Podria pensarse en almacenar pri- mero todas las direcciones que posiblemente se podrén necesitar, y no prestar 22 INTRODUCCION Y CONCEPTOS FUNDAMENTALES: mucha atencién al orden de los enlaces. Sin embargo, esta ‘soluci6n’ no es acepta- ble (aunque ‘funcione’), primero porque se utilizan variables innecesarias, segundo porque la lista se manejarfa de forma ineficaz y tercero porque se complica la legibi- lidad del cédigo. El Programa 1.1 muestra el cédigo necesario para la inserci6n por Ja cabeza de una lista enlazada. Estado inicial Paso 1 Paso 2 Paso 3 Paso 4 lista Nuevo_nodo Nuevo_dato lista Nuevo_nodo Nuevo_dato lista Nuevo_nodo Nuevo_dato lista Nuevo_nodo Nuevo_dato lista Nuevo_nodo Nuevo_dato | Ps Figura 1.12 Pasos necesarios para realizar una insercidn por la cabeza. Las flechas de trazo continuo indican punteros, las de trazo discontinuo indican trasvase de informacion correspondiente 2 una sentencia de asignacion. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 23 Programa 1.1_Insercién por la cabeza de una lista enlazada. soem PROCEDURE Insertar_cabeza(VAR lista:Ptr_Nodo;nuevo_dato:Tipo_datos) ; VAR Nuevo_nodo : Ptr_Nodo; BEGIN ALLOCATE (Nuevo_nodo, SIZE(Nodo) } ; Nuevo_nodo*.datos := nuevo_dato; Nuevo_nodo*. enlace lista := Nuevo_nodo END Insertar_cabeza; Insercién por el final Para insertar por el final deberemos llegar hasta él y hacer la insercién. En pri- mer lugar se crea un nuevo nodo, se introducen los nuevos datos en el campo de datos y como a partir de ahora seré el tltimo elemento se asigna NIL a su campo enlace. Para llegar hasta el final se hace uso de un puntero auxiliar (Actual) que ird recorriendo la lista hasta que localice el final. Para hacer esto podemos elegir una estructura iterativa While, antes de la cual habré que inicializar adecuadamente el puntero temporal (Actual) pata que apunte al primer elemento de la lista (actual:=lista). Dentro del bucle lo tinico que hay que hacer es avanzar este pun- tero (Actual) para que recorra toda la lista pasando de un elemento al siguiente (actual:= Actual*.enlace). Cuando Actual apunte al tltimo nodo, actual” enlace sera NIL. Es entonces cuando hay que salir de la iteracién, con lo que la condicién del bucle serd actual*.enlacecntL y el tiltimo nodo estarfa siendo apuntado por Actual Por tiltimo, se realiza el enlace entre el tiltimo elemento de la lista y el nuevo nodo (Actual*.enlace:=Nuevo_nodo). = No obstante, la condicién del bucle es valida tinicamente para una lista no vaefa, por lo que habré que comprobar este hecho antes de hacer una llamada a este procedimiento. Si la lista esta vacfa, el puntero Actual se inicializarfa a NIL, y por tanto, la condicién del bucle estaria basada en una variable referenciada inexistente. Sin embargo, el caso de insercién por el final de una lista enlazada vacia es el mismo que el de insercién por el principio, problema que ya est4 resuelto. En la Figura 1.13 se muestran los pasos necesarios para una insercién por el final, Como en el resto de las secuencias de figuras que se muestran en este capitulo, cada una muestra la situacién de la estructura después de ejecutar el paso correspon- diente que est4 marcado con un némero a Ia izquierda del cédigo asociado al algo- ritmo. En esta Figura 1.13, el paso 4 indica la situacién de los punteros después de salir del bucle while que aparece en el Programa 1.2. El paso etiquetado en las figu- ras con el ntimero 0 indica el estado inicial antes de comenzar la ejecucién de la insercién o eliminacién, por lo que no aparece en el c6digo correspondiente. 24 INTRODUCCION Y CONCEPTOS FUNDAMENTALES Actual, (0) lista Nuevo_nodo Nuevo_dato 1 lista Nuevo_nodo 2 lista Nuevo_nodo Nuevo_dato Actual 3 lista Nuevo_nodo lista fs Nuevo_nodo 5 lista Nuevo_nodo 1 | ee ge A] : Xx | kK tL EH | . Xk— —_—_—— Figura 1.13 _Insercién por el final de una lista enlazada. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS Programa 1.2. Insercién por el final de una lista enlazada. PROCEDURE Insertar_final(VAR lista:Ptr_Nodo; nuevo_dato:Tipo_datos) ; VAR Nuevo_nodo, Actual : Ptr_Nodo; BEGIN IF lista-nil THEN Insertar_cabeza(lista,nuevo_dato) ELSE Paso 1 ALLOCATE (Nuevo_nodo, S1ZE(Nodo) } ; 2 Nuevo_nodo*.datos := nuevo_dato; Nuevo_nodo*.enlace := NIL; Actual := lista; WHILE Actual*.enlace <> NIL DO Actual := Actual’.enlace; END; Actual*.enlace := Nuevo_nodo 5 END END Insertar_final; aon Suprimir por la cabeza La eliminacién del elemento del principio de la lista consta de cuatro pasos: 25 1. En primer lugar se almacena la direccién de este primer elemento, apuntado por la variable 1ista, en un puntero axiliar (Aux), Aux:=lista; 2. En segundo lugar, habra que asignar al parémetro formal dato, el valor almace- nado en el elemento a eliminar. 3. Seguidamente se realiza la asignacién de la lista al nuevo primer elemento (lista:=lista’.enlace). 4. Por iltimo, se libera la memoria del nodo que ya no pertenece a la lista. Debe tenerse muy en cuenta que el no realizar este tltimo paso, es decir, supri- mir tinicamente mediante la asignacién lista: lista’ .enlace, es un error muy grave. Estarfa ocupdndose memoria no necesaria y a lo largo de la ejecucién del pro- grama el sistema podria quedarse sin memoria libre pese a que en realidad no se uti- liza la memoria que se est4 ocupando. Recuérdese los comentarios realizados previamente y que se ilustraban en la Figura 1.4, Enel so de las listas enlazadas el problema es especialmente grave pues puede resultar reiterativo debido a las nume- TOS estructuras. s inserciones y eliminaciones que normalmente se realizan en este tipo de Obsérvese también que el puntero auxiliar es imprescindible para liberar final- mente el nodo. El c6digo necesario para realizar la supresién por la cabeza se mues- tra en el Programa 1.3 y la Figura 1.14 ilustra los pasos necesarios. 26 INTRODUCCION Y CONCEPTOS FUNDAMENTALES aux [9] 0) 1istale a : x dato Aux lista |« . . +>) |X Aux | ¢}— 2 lista|« . et |X dato] < aux | ¢|— sy] lista aux [2] lista |e, Figura 1.14 Supresién por la cabeza de una lista enlazada. Programa 1.3 Supresién por la cabeza de una lista enlazada. PROCEDURE Suprimir_cabeza(VAR lista: Ptr_Nodo;VAR dato: Tipo_datos); VAR Aux : Ptr_Nodo; BEGIN Paso 1 Aux := lista; 2 dato := lista*.datos; 3 lista:=lista*.enlace; 4 DEALLOCATE (Aux, SIZE (Nodo) ) ; END Suprimir_cabeza; ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 27 Suprimir por el final La supresi6n por el final requiere l6gicamente localizar la tiltima posicién de la lista y liberar el dltimo nodo. Pero ademis, sera imprescindible asignar el valor NIL al pentiltimo elemento de la misma, que tras la eliminaci6n pasaré a ser el tiltimo, ya que de no ser asf la lista no tendria final y el tltimo enlace estaria apuntando a una direccién, de memoria desconocida (y posiblemente utilizada para otro cometido, como por ejemplo otra variable), con lo que los recorridos sobre ella no tendrfan fin. Para ello se utiliza un puntero auxiliar (Actual) que apuntaré al final del reco- rrido (al final del bucle) al tiltimo elemento, y otro puntero (ant) que quedard apun- tando al anterior. Con una estructura iterativa while la condicién de salida del bucle serd Actual*.enlace<>NIL. Por tiltimo, se realiza la eliminacién del Ultimo nodo y se asigna NIL al nuevo ultimo nodo (ant*.enlace:=NIL). E] Programa 1.4 muestra el cédigo necesario para la supresién por el final de una lista enlazada implementado en Modula2. La Figura 1.15 muestra la secuencia de pasos correspondiente. Las acciones necesarias para la supresin por el final de una lista enlazada pue- den resumirse en los siguientes pasos: * Inicializacién de los punteros. * Recorrido de la lista hasta alcanzar el final. * Recuperacién de] dato almacenado en el tiltimo nodo. * Eliminacién del nodo y marcado del nuevo tiltimo nodo. Programa 1.4 Supresién por el final de una lista enlazada. Paso 1 © PROCEDURE Suprimir_final(VAR lista: Ptr_Nodo; VAR dato: VAR Actual, Anterior : Ptr_Nodo; BEGIN anterior := lista; Actua. ista; WHILE Actual*.enlace <> NIL DO Anterior Actual; Actual := Actual*.enlace EN dato Actual*.datos; anterior*.enlace := NIL; IF Anterior=Actual THEN (*si sélo hay un nodo*) lista:=NIL END DEALLOCATE (Actual , SIZE (Nodo) ) END Suprimir_final; Tipo_datos) ; 28 INTRODUCCION Y CONCEPTOS FUNDAMENTALES: anterior [9] 2] Actual 0) iistafe}—t ]- . f X dato anterior [+}~ @] Actual 1 ¥ lista | +|- . . ++ x : anterior [+ +] actual 2 4 7 lista[e. +} of [-}--— J4 | x Anterior [« |~ actual 3) lista[s . ° . X dato | < }~ o} actual 4) a I usta] OT} oe x Ti Figura 1.15 Supresién por el final de una lista enlazada en el caso general de que tenga més de un nodo. Insercién segiin un criterio de orden Otra funcién tipica sobre listas enlazadas es insertar en el medio. Para ello habré que hacerlo segtin un criterio. Sup6ngase que la lista se utiliza para almacenar ntimeros enteros (Tipo_datos=INTEGER) y que la lista esta ordenada en sentido cre- ciente. El algoritmo que se describe a continuacién, inserta un nuevo numero entero en su lugar y la Figura 1.16 muestra los pasos necesarios. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 29 anterior [32] ° lista |« 5 *}—>/25 |¢] - - —>150]X Nuevo_nodo |¢?| 19 |dato lista [« 5 |e 8 [+}-—>f25]+} .- —f50]X Nuevo_nodo 1) dato [19 anterior [«]- o}. actual 2 rista |+|—>} 5 |-}—5) 8 |-| Jas]. 50/X Nuevo_nodo | ¢}---> 19 |g?| Anterior |e . Actual 3 lista |e 5 |e 8 |e 25}° 50 |X Muevo_nodo | * 19 |e] Anterior |e . Actual 4 uista [+] of 5 ]~ |. 25]« 50 |X Nuevo_nodo | + 19] + Anterior |e . Actual 5 usta [-} fs [+] ale 25|+| 50 ]X Nuevo_nodo Figura 1.16 Insercion en orden en una lista enlazada delante de Actual. 30 INTRODUCCION Y CONCEPTOS FUNDAMENTALES En general, deben considerarse tres situaciones posibles: que la posicién a insertar sea Ja primera, la tltima o una entre éstas. Localizada la situacién en la que es necesario insertar al principio (datoNIL)AND(NOT Encontrado) DO IF dato>Actual*.datos THEN Anterior :=Actual; Actual: =Actual” enlace ELSE Encontrado END; END; (*Insertar el nuevo nodo*) Nuevo_nodo*. enlace: =Actual; Anterior*.enlace:=Nuevo_nodo END; END Insertar_orden,delante; "RUE; Este procedimiento también podria haberse realizado insertando el nuevo nodo por detrds del puntero Actual, tal y como se muestra en las Figuras 1.17 y 1.18. Para conseguir esto, se avanza sobre la lista de la misma forma que en los casos anterio- res, pero ahora al encontrar el elemento mayor (si existe) se realiza la insercién den- tro del mismo bucle. Esto se hace en tres pasos, el primero consiste en copiar el contenido del nodo referenciado por el puntero de recorrido (Actual*) en el nuevo nodo (paso 4 de la Figura 1.17). A continuacién, el enlace del nodo al que apunta Actual se hace que apunte al nuevo nodo (Actual*.enlace:=Nuevo_nodo), con lo que la insercién se produce efectivamente detrés del puntero Actual. Por ultimo, se asigna el valor del nuevo dato al campo datos del nodo apuntado por Actual (Nuevo_nodo*.datos:=dato). El paso 5 de la Figura 1.17 ilustra estas dos tltimas acciones y el Programa 1.6 muestra el cédigo correspondiente. 32 Anterior lista Nuevo_nodo lista Nuevo_nodo Anterior lista Nuevo_nodo 3 lista Nuevo_nodo lista Nueve_nodo 5 lista Nuevo_nodo dato INTRODUCCION Y CONCEPTOS FUNDAMENTALES 2 9] actual fs {2 {12 25] 50 \2?| 19 |dato . 5]e 8 [-| fr2[-} fas] -] foo . 2? |e] . +} actual : 5° 8 ]+}—fi2] +} Jas] -] —fe0 . 2? |e? anterior |e] ot} actual offs > 8 |+|—>}12]-]| J2s]-]- [50 +12? ke? Encontrado=True anterior [+ +}. actual s . 5 |e 8 | +} [12] +] 25+] [50 ae = +} fas] __— anterior [+ +} actual . 8 |- Ble «| [50 | Jos] os 19 Figura 1.17 Insercién en orden en una lista enlazada (detras de Actual). ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 33 Programa 1,6 Insercién en una lista enlazada segun un criterio (detrés de Actual). Paso 1 oa o PROCEDURE Insertar_orden_detras (VAR lista: Ptr_Nodo; dato : Tipo_datos); VAR Encontrado : BOOLEAN; Actual, Nuevo_nodo, Anterior : Ptr_Nodo; BEGIN IF (lista=NIL) OR (dato Actual*.datos THEN Anterior:=Actual; Actual:=Actual*.enlace ELSE Nuevo_nodo*:=Actual*; Actual”. enlace:=Nuevo_nodo; Actual*.datos:=dato; Encontrado:=TRUE; END; END; IF NOT Encontrado THEN (* Insercion al final *) Nuevo_nodo*.datos:=dato; Nuevo_nodo*.. enlac: Anterior* enlace END END END Insertar_orden_detras; Sin embargo, la solucién que se acaba de comentar no es valida para el caso en el que todos los elementos son menores que el nuevo, ya que el bucle terminaré sin que se haya realizado la insercién, puesto que en ninguna de las iteraciones habré dejado de cumplirse la condicion dato>Actual*.datos que es la que realiza la inser- cién comentada en el parrafo anterior. Por este motivo, esta situacién hay que tra- tarla aparte, fuera del bucle, lo que se ilustra en los pasos 6 y 7 de la Figura 1.18. Hay que tener en cuenta que esta figura no es una continuacién de la anterior, sino una alternativa a los pasos 4 y 5 de la misma. Este hecho queda claramente de manifiesto en el cédigo correspondiente que se muestra en el Programa 1.6. En este programa se muestra que si se ejecutan los pasos 4 y 5 dentro del bucle la variable booleana Encontrado toma el valor True lo que impide que se ejecuten los pasos 6 y 7 externos al bucle. 34 INTRODUCCION Y CONCEPTOS FUNDAMENTALES Andlogamente puede desarrollarse un procedimiento para suprimir segin un criterio dado. Encontrado=false anterior |e}—_ actual |X 6 lista | 5 le 8 | 12 | ¢}-—>} 25 | 50 |X Nuevo_nodo| * 751K ae 75 NIL Encontrado=false Anterior |*}. Actual |X| 7 lista | 5 fe 8 |e 12| + Nuevo_nodo Figura 1.18 Insercién en orden en una lista enlazada por detras del puntero de recorrido, en el caso en que el nuevo elemento sea mayor que todos los de la lista. Imprimir una lista enlazada Evidentemente imprimir los datos de la lista enlazada serd una tarea habitual. Esto puede realizarse en orden, es decir, de manera que aparezcan los datos de prin- cipio a fin de la lista tal y como muestra el Programa 1.7 Programa 1.7 Imprimir una lista enlazada en orden. PROCEDURE Imprimir_lista(lista : Ptr_Nodo); VAR Aux : Ptr_Nodo; BEGIN Aux := lista; WHILE Aux <> NIL DO WriteInt (Aux*.datos,7); Aux := Aux*.enlace; END; END Imprimir_lista; Sin embargo, también es posible imprimirla en orden inverso recorriendo una sola vez la lista mediante una implementaci6n recursiva, tal y como se muestra en el Programa 1.8. ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS 35 Programa 1.8 Imprimir una lista enlazada en orden inverso. PROCEDURE Imprimir_contrario (lista: Ptr_Nodo); BEGIN IF lista <> NIL THEN Imprimir_contrario(lista* enlace) ; Writelnt (Lista®.datos, 6) ; END; END Imprimir_contrario; Las operaciones sobre listas enlazadas mostradas en este apartado tienen como fin fundamental ilustrar el manejo de los punteros, pero por supuesto no son las tini- cas posibles. Cualquier operacién que fuese requerida para la solucién de un pro- blema se realizaré manejando los punteros de forma andloga a la aqui presentada. 1.2.5 TDA LISTA IMPLEMENTADO CON LISTAS ENLAZADAS Por tiltimo, es evidente que cuando el TDA lista se implementa con listas enla- zadas, sus operadores asociados se implementan andlogamente. Seguidamente se presentan todos ellos. Es importante analizarlos detalladamente como ejercicio de programaci6n con listas enlazadas. Programa 1 Insercién en una lista en una posicion PROCEDURE Insertar (VAR L: Ptr_Nodo; x : Tipo_datos;p: INTEGER) ; (* Inserta un elemento, x, en una posicion p de L, pasando los elementos de la posicion p y siguientes a la posicion inmediatamente posterior *) VAR Anterior, Actual, Nuevo_nodo: Ptr_Nodo; cont: INTEGER; BE IF p=1 THEN (*Inserta en la primera posicion*) ALLOCATE (Nuevo_nodo, SIZE {Nodo} } ; Nuevo_nodo*. datos Nuevo_nodo*. enlace: Li ELSE WHILE (Actual#NIL)&(cont#p) DO Anterior: =Actual; Actual :=Actual* enlace; cont :=cont+1 END; IF pscont+l THEN (* p menor que el numero de elementos de L *) 36 INTRODUCCION Y CONCEPTOS FUNDAMENTALES ALLOCATE (Nuevo_nodo, $1ZE(Nodo) } ; Nuevo_nodo*. datos: =x; Anterior” .enlace:=Nuevo_nodo; IF (Actual=NIL}OR((Actual=L)&(cont=p-1)) THEN (* insertar en la ultima posicion *) Muevo_nodo*. enlace: =NIL ELSIF cont=p THEN (*insertar en posicion intermedia*) Nuevo_nodo*. enlace: =Actual; END END END END Inserar; Programa 1.10 Localizacién de la posicién de un determinado elemento pasado como pardmetro. PROCEDURE Localizar (L: Ptr_Nodo; x : Tipo_datos) : INTEGER; (* Localiza la posicion en la que se encuentra un elemento dado x, si no lo encuentra devuelve 0 *) VAR Actual, Anterior: Ptr_Nodo; Encontrado: BOOLEAN; Pp: INTEGER; BEGIN Anterior:=NIL; Actual:=L; p:=0; Encontrado:=FALSE; WHILE NOT Encontrado & (Actual#NIL) DO IF Actual*.datos=x THEN ‘TRUE; :sActual; ctual* enlace; IF NOT Encontrado THEN p:=0; (*Elemento no encontrado*) ELSE Actual:=Actual*.enlace; END, RETURN p END Localizar; ESTRUCTURAS DE DATOS Y TIPOS DE DATOS ABSTRACTOS Programa 1.11 _Obtencién de la posicién de un elemento dado como pardmetro. PROCEDURE Recuperar (L: Ptr_Nodo; VAR x VAR encontrado: BOOLEAN) ; : Tipo_datos;p: INTEGER; (* Encuentra el elemento x que esta en la posicion p, si la posicion p es mayor que el numero de elementos de L, devuelve VAR Actual: Ptr_Nodo; cont : INTEGER; BEGIN encontrado: =FALSE; Actua’ cont:=1; WHILE (Actual#NIL)&(cont, ...,4, , tal que cada ele- mento a; tiene una clave asociada, clave[a,]. Se dice que existe una relacién de orden sobre las claves si para tres valores cualesquiera de la clave, clave(a)), clave[d,] y clave[a,] se satisface que: 1, clavefaj]clavelap] 2. Si clavelaj} im (2 +n-2) 2 52 CLASIFICACION EN MEMORIA PRINCIPAL, 2 y por tanto: Cope = RH?) ‘max 2 c) Caso promedio: las llaves iniciales estan aleatoriamente ordenadas. En el caso promedio las Ilaves del arreglo inicial estén ordenadas aleatoria- mente. Por ello para realizar el andlisis habré que hacer uso de argumentos probabi- Uisticos atendiendo a la comparacién (a{0]| 15} 60) 7) 4 3114/17] 20 | 22 2 46 59}15 460) 7.1 — a 3 2 7 : 40 15} 60] 7 | 1 a SSS SOS SS SS Figura 2.3 Busqueda dicotémica de la posicién para la insercion. Programa 2.2 Implementacién del algoritmo de insercién binaria. VAR i,t,m,L,R: Tipo_indice;x: Tipo_datos; BEGIN {* Li indice al elemento de la parte izquierda del subarray en el que se realiza la bisqueda en cada paso *) indice al elemento de la parte derecha del subarray en el gue se realiza la biisqueda en cada paso *) R WHILE LR DO m:=(L4R)DIV 2; METODOS DIRECTOS DE CLASIFICACION IF alm]0, el ntimero de movimientos promedio en cada pase i serd a M, (promi = Ini+y+1 Sumando para todos los pases obtenemos: Myrom = RY+ Lt ym i=l Finalmente, aproximando por la integral: prom Myrom = nye) +f Inxdx 1 62 CLASIFICACION EN MEMORIA PRINCIPAL 2.2.4 y tesolviendo j (Inx)dx = x(Inx-1)|} como ya se hizo con la Integral 2.2 se 1 obtiene: M = n(y+1)+2x(Inx- 1)[} =n(Inn +) prom En conclusi6n: Myrom= (Inn +) prom Este resultado permite concluir que el método de seleccién directa es preferible al de la insercidn directa ya que su ntimero de movimientos promedio es de orden Inn. Pero si se compara con la insercién binaria cabe preguntarse cudl es més ade- cuado ya que tiene un coste de orden n? para los movimientos pero logn para las comparaciones, mientras que en la seleccién directa es de orden n? para las compa- raciones y Inn para los movimientos. La decisi6n en esta situacion viene determi- nada por consideraciones de bajo nivel. En general, la implementacién de una comparacién tiene un coste inferior al de un movimiento. Por tanto, la seleccién directa seré la opcién a elegir en general, aunque la insercion es algo més répida cuando las Haves se clasifican predominantemente al principio. En algunas ocasiones puede sorprender que en el andlisis del caso promedio se obtenga un coste significativamente menor que en el peor cuando en este ultimo s6lo se realizan asignaciones de seleccién (x:=a[k]) hasta n/2, mientras que en el primero hay que analizar hasta n. Debe observarse que en el caso peor aunque sélo sea hasta n/2, se ejecutan todas, mientras que en el promedio aunque es hasta n s6lo se realizan segiin los argumentos probabilisticos. Por ello, el hecho de que sea hasta n/2 no implica una reducci6n sensible del coste computacional. CLASIFICACION POR INTERCAMBIO DIRECTO La idea bisica es comparar parejas de elementos contiguos e intercambiarlos si es necesario. En un primer paso se recorre el arreglo en sentido ascendente comen- zando por el principio, comparando parejas de Ilaves. Si el elemento anterior es mayor se intercambian, si es menor no, y en ambos casos se sigue avanzando. En conclusién, el algoritmo puede describirse de la siguiente forma: + Comparar pares de elementos contiguos. * Intercambiarlos si estén desordenados. La Figura 2.7 muestra cada paso hasta obtener la ordenacién final de un arreglo de siete elementos. METODOS DIRECTOS DE CLASIFICACION 63 1* pasada 6* pasada 1 iteracion jet j=4 25 556 8 8 8 8 a4) [a4] 5 5 5 5 5] 9 9 9 9 9 3 3 3 3 3 “AE 14 14] Giteraciones 23) [23 [23] faa}. [7 i) [7 7] [47] [2 I 5 5 [5a] 8 8 9] fol 3 3] on aE g : S| 2tpasada 14 14 [14 14 5 iteraciones 17 17 [17] 17 23 23 23 23 5 5 5 rs) [el 3 3] [3] 8] 3 pasada 9 9 9 14 14 14 4 iteraciones 7) [az 17 23) [23 23 3 3 3 3 31° 5 5 : 8 re} [el 8] 4° pasada doe eo) 9 [9] g 74) [74] [44] [94] 3 iteraciones w7| [a7] [a7] [az 23} ([23| [23] [23 3 3 [5 5 (8 8 | 5% pasada 9 9 74) [44] [44] 2 iteraciones 7] a7] az 23| [23) [23 Figura 2.7 Descripcién de la clasificacién por intercambio directo. Los elementos que se comparan en cada iteracién estén marcados por un rectangulo redondeado. Las aspas indican intercam- bios entre una iteracién y la siguiente y los elementos sombreados forman la parte ordenada del arreglo en cada momento. 64 CLASIFICACION EN MEMORIA PRINCIPAL, Veamos detalladamente el primer pase. Se elige el a{1] (el 8) y se compara con el siguiente, a(2] (el 14), y como estén en orden (el primero es menor que el segundo) se dejan en sus respectivas posiciones. Seguidamente se compara a[2} (el 14) con el siguiente a{3] (el 5) y como entre ellos estén desordendados se intercam- bian. Asf sucesivamente se comparan a(3] (nuevamente el 14) con a[4] (el 9) y hay intercambio, a[4] (el 14) con a[5] (el 3) y hay intercambio, a(5] (otra vez él 14) con a[6] (el 23) y no hay intercambio y finalmente a(6] (el 23) con a(7} (el 17) y hay intercambio. La parte superior de la Figura 2.7 muestra este pase con detalle, donde se han marcado los elementos que se comparan en cada iteracién y mediante un aspa los intercambios entre iteraciones sucesivas. El Programa 2.4 implementa en Modula2 este algoritmo, que es conocido como método de la burbuja debido a que en cada pase van ascendiendo (0 como en este caso descendiendo) elementos hacia su posicién. Obsérvese, por ejemplo el niimero 14 que ha intervenido en varias comparaciones e intercambios. Si hubiese sido el mayor de todos, no habria parado de ‘burbujear’ hasta llegar al final que seria su posicién definitiva. En cada pasada, el método de la burbuja, garantiza que el mayor de los elementos se sittia en su posicién definitiva (la tltima). Programa 2.4 Implementacién del algoritmo de intercambio directo. i,j 1 Tipo_indice; aux : Tipo_datos; FOR i:=1 T0 n-1 DO 10 n-i DO (* Comparar elementos contiguos *) (* Intercambiar *) Anilisis de la clasificacién por intercambio directo Las operaciones més frecuentes caracteristicas del algoritmo son 1a compara- cién de elementos del arreglo (a(j]>a{j+1)), y los movimientos entre elementos del arreglo (aux:=a{j+i], alj+1]:=a(j) y a{j]:2aux), y como es habitual, el andlisis asint6tico requiere el célculo del nimero de comparaciones y de movimientos en los casos mejor, peor y promedio y no se consideran las operaciones auxiliares. También en este algoritmo, al igual que en el de selecci6n directa, el nimero de comparaciones es independiente del orden inicial de las Ilaves del arreglo ya que METODOS DIRECTOS DE CLASIFICACION 65 siempre se recorre por completo la parte desordenada del arreglo para comparar las parejas de claves adyacentes. Para los movimientos, por el contrario, si se distinguen diferentes casos. Cuando el arreglo esté completamente ordenado no hay ningdn intercambio. Cuando esta ordenado en orden inverso se realizaré un intercambio con cada comparacién, es decir, se realizan todos los intercambios posibles. Asf el mejor caso para los movimientos se dard cuando el arreglo esté inicialmente ordenado y el peor caso cuando esté completamente desordenado (ordenado en sentido inverso) presentando, por tanto, un comportamiento natural. Atendiendo al Programa 2.4 el andlisis del algoritmo es el siguiente: - Comparaciones Es independientemente del orden inicial de las Ilaves. La comparaci6n (a{j]>a(J+1}) se realizard n—1 veces para el primer pase (/=2), n-2 en el segundo (i=3) y as{ sucesivamente hasta el ultimo pase en el que realiza una comparacin. Sumando todas ellas se observa que es una suma aritmética y por tanto, el niimero de comparaciones serd de orden n?. Ast: - Movimientos a) Mejor caso: las llaves estan inicialmente ordenadas. En esta situaci6n nunca se entra en el TF, por tanto el intercambio, formado por tres movimientos (aux:=a(j+1}, a{j+1]:=a[j] y a{j]:=aux), no se realiza nunca. Por tanto: b) Peor caso: las llaves iniciales estén completamente desordenadas. En este caso se realiza el intercambio siempre que se realiza la comparacién. Por lo que tenemos: Mmnax = 3C max cM Max = 3 c) Caso promedio: las llaves iniciales estén aleatoriamente ordenadas. En el caso promedio las llaves del arreglo inicial estén ordenadas aleatoria- mente y habré que utilizar argumentos probabilfsticos. El intercambio se realizaré

You might also like