You are on page 1of 62

ESTRUCTURA DE DATOS

Cuadernillo
El alumno aplicar las clases de la biblioteca estndar STL del lenguaje C++ y ser capaz de manejar las estructuras de datos dinmicas, para la elaboracin de programas utilizando la programacin orientada a objetos. L.I. Octavio Molina Aguilar 13/07/2011

INTRODUCCIN.............................................................................................................................. 3 TEMA 1 .......................................................................................................................................... 4 ANTECEDENTES. ............................................................................................................................. 4 1.1 Introduccin a la orientacin a objetos. ................................................................................ 4 1.2 Tipos de datos abstractos. .................................................................................................... 6 1.3 Definicin de estructuras de datos. ....................................................................................... 7 1.4 Colecciones genricas de datos............................................................................................. 8 1.5 Acceso directo y secuencial a los datos. .......................................................................... 9

1.6 Iteradores. .......................................................................................................................... 10 1.7 Plantillas (templates). ......................................................................................................... 11 1.8 La biblioteca STL. ................................................................................................................ 13 Preguntas de autoevaluacin. .................................................................................................. 15 TEMA 2 ........................................................................................................................................ 16 ARREGLOS. ................................................................................................................................... 16 2.1 Arreglos lineales dinmicos................................................................................................. 16 2.2 Representacin de arreglos lineales en memoria ................................................................ 18 2.3 Operaciones con arreglos. .................................................................................................. 19 2.4 Arreglos dinmicos. ............................................................................................................ 20 2.5 Punteros y arreglos de punteros. ........................................................................................ 21 2.6 La clase VECTOR. ................................................................................................................ 23 Preguntas de autoevaluacin. .................................................................................................. 25 TEMA 3 ........................................................................................................................................ 26 LISTAS. ......................................................................................................................................... 26 3.1 Definicin de lista. .............................................................................................................. 26 3.2 Asignacin de memoria a la lista. ........................................................................................ 27 3.3 La clase lista de STL. ............................................................................................................ 28 3.4 Iteradores para la clase lista................................................................................................ 29 3.5 Construccin de listas. ........................................................................................................ 32 3.6 Algoritmos genricos sobre colecciones de STL. .................................................................. 33 Preguntas de autoevaluacin. .................................................................................................. 34 TEMA 4 ........................................................................................................................................ 35 PILAS. ........................................................................................................................................... 35

4.1 Definicin de pilas. ............................................................................................................. 35 4.2 Implementacin de pilas. .................................................................................................... 36 4.3 La clase STACK de STL ......................................................................................................... 37 4.4 Iteradores para la clase Stack. ............................................................................................. 39 4.5 Construccin de Pilas. ......................................................................................................... 40 Preguntas de autoevaluacin. .................................................................................................. 42 TEMA 5 ........................................................................................................................................ 43 COLAS. ......................................................................................................................................... 43 5.1 Definicin de colas. ............................................................................................................. 43 5.2 Construccin de colas. ........................................................................................................ 44 5.3 La clase queue de STL. ........................................................................................................ 45 5.4 Iteradores para la clase Queue. .......................................................................................... 46 Preguntas de autoevaluacin. .................................................................................................. 48 TEMA 6 ........................................................................................................................................ 49 ARBOLES. ..................................................................................................................................... 49 6.1 Definicin de rbol. ............................................................................................................ 49 6.2 rboles binarios. ................................................................................................................. 51 6.3 Representacin de rboles binarios en memoria. ............................................................... 52 6.4 Recorrido de rboles........................................................................................................... 53 6.5 Arboles binarios de bsqueda. ............................................................................................ 55 6.6 Bsqueda e insercin de rboles binarios de bsqueda. ..................................................... 56 6.7 rboles degenerados. ......................................................................................................... 57 6.8 Aplicaciones de rboles. ..................................................................................................... 58 Preguntas de autoevaluacin. .................................................................................................. 59 CONCLUSIONES ............................................................................................................................ 60 BIBLIOGRAFA .............................................................................................................................. 61

INTRODUCCIN.
El ANSI define un conjunto de reglas. Cualquier compilador de C o de C++ debe cumplir esas reglas, si no, no puede considerarse un compilador de C o C++. Estas reglas definen las caractersticas de un compilador en cuanto a palabras reservadas del lenguaje, comportamiento de los elementos que lo componen, funciones externas que se incluyen, etc. Un programa escrito en ANSI C o en ANSI C++, podr compilarse con cualquier compilador que cumpla la norma ANSI. Se puede considerar como una homologacin o etiqueta de calidad de un compilador. Todos los compiladores incluyen, adems del ANSI, ciertas caractersticas no ANSI, por ejemplo libreras para grficos. Pero mientras no usemos ninguna de esas caractersticas, sabremos que nuestros programas son transportables, es decir, que podrn ejecutarse en cualquier ordenador y con cualquier sistema operativo. Junto con los compiladores de C y C++, se incluyen ciertos ficheros llamados libreras. Las libreras contienen el cdigo objeto de muchos programas que permiten hacer cosas comunes, como leer el teclado, escribir en la pantalla, manejar nmeros, realizar funciones matemticas, etc. Las libreras estn clasificadas por el tipo de trabajos que hacen, hay libreras de entrada y salida, matemticas, de manejo de memoria, de manejo de textos, etc. Hay un conjunto de libreras muy especiales, que se incluyen con todos los compiladores de C y de C++. Son las libreras ANSI o estndar. Pero tambin hay libreras no estndar, y dentro de estas las hay pblicas y comerciales. En este nos centraremos en la librera estndar STL.

TEMA 1 ANTECEDENTES.
Presentar a los alumnos las estructuras de datos bsicas y su transformacin en estructuras ms complejas. Se pretende que los alumnos puedan definir o elegir estructuras adecuadas para la resolucin de problemas especficos de la vida real apoyados en las tcnicas computacionales.

1.1 Introduccin a la orientacin a objetos.


La programacin orientada a objetos (POO) es una nueva manera de enfocar la programacin. Desde sus comienzos, la programacin ha estado gobernada por varias metodologas. En cada punto crtico de la evolucin de la programacin se creaba un nuevo enfoque para ayudar al programador a manejar programas cada vez ms complejos. Los primeros programas se crearon mediante un proceso de cambio de los conmutadores del panel frontal de la computadora. Obviamente, este enfoque solo es adecuado para programas pequeos. A continuacin se invent el lenguaje ensamblador que permiti escribir programas ms largos. El siguiente avance ocurri en los aos 50 cuando se invent el primer lenguaje de alto nivel (FORTRAN). Mediante un lenguaje de alto nivel, un programador estaba capacitado para escribir programas que tuvieran una longitud de varios miles de lneas. Sin embargo, el mtodo de programacin usado en el comienzo era un enfoque adhoc que no solucionaba mucho. Mientras que esto est bien para programas relativamente cortos, se convierte en cdigo espagueti ilegible y difcil de tratar cuando se aplica a programas ms largos. La eliminacin del cdigo espagueti se consigui con la creacin de los lenguajes de programacin estructurados en los aos sesenta. Estos lenguajes incluyen ALGOL y PASCAL. En definitiva, C es un lenguaje estructurado, y casi todos los tipos de programas que se han estado haciendo se podran llamar programas estructurados. Los programas estructurados se basan en estructuras de control bien definidas, bloques de cdigo, la ausencia del GOTO, y subrutinas independientes que soportan recursividad y variables locales. La esencia de la programacin estructurada es la reduccin de un programa a sus elementos constitutivos. Mediante la programacin estructurada un programador medio puede crear y mantener programas de una longitud superior a 50,000 lneas. Aunque la programacin estructurada nos ha llevado a excelentes resultados cuando se ha aplicado a programas moderadamente complejos, llega a fallar en algn punto cuando el programa alcanza un cierto tamao. Para poder escribir programas de mayor complejidad se necesitaba de un nuevo enfoque en la tarea de programacin. A partir de este punto nace la programacin orientada a objetos (POO). La POO toma las mejores ideas incorporadas en la programacin estructurada y las combina con nuevos y potentes conceptos que permiten

organizar los programas de forma ms efectiva. La POO permite descomponer un problema en subgrupos relacionados. Cada subgrupo pasa a ser un objeto autocontenido que contiene sus propias instrucciones y datos que le relacionan con ese objeto. De esta manera, la complejidad se reduce y el programador puede tratar programas ms largos. Todos los lenguajes de POO comparten tres caractersticas: encapsulacin, polimorfismo y herencia. La encapsulacin es el mecanismo que agrupa el cdigo y los datos que maneja y los mantiene protegidos frente a cualquier interferencia y mal uso. En un lenguaje orientado a objetos, el cdigo y los datos suelen empaquetarse de la misma forma en que se crea una caja negra autocontenida. Dentro de la caja son necesarios tanto el cdigo como los datos. Cuando el cdigo y los datos estn enlazados de esta manera, se ha creado un objeto. En otras palabras, un objeto es el dispositivo que soporta encapsulacin. Polimorfismo (del Griego, cuyo significado es muchas formas ) es la cualidad que permite que un nombre se utilice para dos o ms propsitos relacionados pero tcnicamente diferentes. El propsito del polimorfismo aplicado a la POO es permitir poder usar un nombre para especificar una clase general de acciones. Dentro de una clase general de acciones, la accin especfica a aplicar est determinada por el tipo de dato. El polimorfismo se puede aplicar tanto a funciones como a operadores, prcticamente todos los lenguajes de programacin contienen una aplicacin limitada de polimorfismo cuando se relaciona con los operadores aritmticos, por ejemplo, en C, el signo + se utiliza para aadir enteros, enteros largos, caracteres y valores reales. En estos casos, el compilador automticamente sabe qu tipo de aritmtica debe aplicar, en C++, se puede ampliar este concepto a otros tipos de datos que se definan, este tipo de polimorfismo se llama sobrecarga de operadores. La herencia es el proceso mediante el cual un objeto puede adquirir las propiedades de otro. Mas en concreto, un objeto puede heredar un conjunto general de propiedades a alas que puede aadir aquellas caractersticas que son especficamente suyas. La herencia es importante porque permite que un objeto soporte el concepto de clasificacin jerrquica. Mucha informacin se hace manejable gracias a esta clasificacin, por ejemplo, la descripcin de una casa. Una casa es parte de una clase general llamada edificio, a su vez, edificio es una parte de la clase ms general estructura, que es parte de la clase an ms general de objetos que se puede llamar obra-hombre.

1.2 Tipos de datos abstractos.


Los tipos de datos abstractos (TDA) encapsulan datos y funciones que trabajan con estos datos. Los datos no son visibles para el usuario en un tipo de dato abstracto y el acceso a los datos es exclusivamente bajo el llamado a funciones, tambin llamadas mtodos. As, el tipo de dato abstracto es especificado por los mtodos, no por los datos. En C++, los tipos de datos abstractos son representados por clases, las cuales presentan a pequea deficiencia: el dato que representa el estado de un objeto de este tipo de dato abstracto es visible (algunas veces no accesible) en la parte private de la clase declarada para cada programa, la clase es reconocida mediante la va #include. Ejemplos de tipos de datos abstractos son: stack, queue, etc Los TDA por lo general manejan memoria dinmica, esto es, la asignacin dinmica de memoria es una caracterstica que le permite al usuario crear tipos de datos y estructuras de cualquier tamao de acuerdo a las necesidades que se tengan en el programa, para ello se emplean funciones tpicas como malloc y free.

1.3 Definicin de estructuras de datos.


En programacin, una estructura de datos es una forma de organizar un conjunto de datos elementales (un dato elemental es la mnima informacin que se tiene en el sistema) con el objetivo de facilitar la manipulacin de estos datos como un todo y/o individualmente. Una estructura de datos define la organizacin e interrelacionamiento de estos, y un conjunto de operaciones que se pueden realizar sobre l. Las operaciones bsicas son:  Alta, adicionar un nuevo valor a la estructura.  Baja, borrar un valor de la estructura.  Bsqueda, encontrar un determinado valor en la estructura para realizar una operacin con este valor, en forma SECUENCIAL o BINARIO (siempre y cuando los datos estn ordenados). Otras operaciones que se pueden realizar son: y y Ordenamiento, de los elementos pertenecientes a la estructura. Apareo, dadas dos estructuras originar una nueva ordenada y que contenga a las apareadas.

1.4 Colecciones genricas de datos.


Cada estructura ofrece ventajas y desventajas en relacin a la simplicidad y eficiencia para la realizacin de cada operacin. De esta forma, la eleccin de la estructura de datos apropiada para cada problema depende de factores como las frecuencias y el orden en que se realiza cada operacin sobre los datos. Algunas estructuras de datos utilizadas en programacin son:  Arrays (Arreglos) o Vectores o Matrices  Listas Enlazadas o Listas Simples o Listas Dobles o Listas Circulares  Pilas (stack)  Colas (queue)  rboles o rboles Binarios  rbol binario de bsqueda y rbol binario de bsqueda autoajustable y rboles Biselados (rboles Splay) o rboles Multicamino (Multirrama)  rboles B  rboles B+  rboles B*  Conjuntos (set)  Grafos  Montculos (o heaps)

1.5

Acceso directo y secuencial a los datos.

 Secuencial. Para acceder a un objeto se debe acceder a los objetos almacenados previamente en el archivo. El acceso secuencial exige elemento a elemento, es necesario una exploracin secuencial comenzando desde el primer elemento.  Directo o Aleatorio. Se accede directamente al objeto, sin recorrer los anteriores. El acceso directo permite procesar o acceder a un elemento determinado haciendo una referencia directamente por su posicin en el soporte de almacenamiento.

1.6 Iteradores.

Un iterador es una especie de puntero utilizado por un algoritmo para recorrer los elementos almacenados en un contenedor. Dado que los distintos algoritmos necesitan recorrer los contenedores de diversas maneras para realizar diversas operaciones, y los contenedores deben ser accedidos de formas distintas, existen diferentes tipos de iteradores. Cada contenedor de la Librera Estndar puede generar un iterador con funcionalidad adecuada a la tcnica de almacenamiento que utiliza. Es precisamente el tipo de iterador requerido como argumento, lo que distingue que algoritmos STL pueden ser utilizados con cada clase de contenedor. Por ejemplo, si un contenedor solo dispone de iteradores de acceso secuencial, no pueden utilizarse con algoritmos que exijan iteradores de acceso aleatorio. Un puntero es una variable destinada a contener una direccin de memoria. Esta direccin generalmente corresponde a otra variable, decimos entonces que el puntero contiene la direccin de la variable o que apunta a sta. En el siguiente esquema suponemos que la variable puntero est cargada con el nmero 4A20. Decimos, entonces, que la direccin 0x4A20 es apuntada por el puntero.

Entre las ventajas que encontramos al usar estos elementos estn: 1) Permiten el acceso a cualquier posicin de la memoria, para ser leda o para ser escrita (en los casos en que esto sea posible). 2) Permiten la transferencia de argumentos a las funciones, de modo que puedan retener un valor nuevo, que resulta de aplicarles la funcin. 3) Permiten solicitar memoria que no fue reservada al inicio del programa. Esto es el uso de memoria dinmica. 4) Son el soporte de enlace que utilizan estructuras avanzadas de datos en memoria dinmica como las listas, pilas, colas y rboles. 5) Operan ms eficientemente en los arrays, en comparacin con el uso de subndices.

10

1.7 Plantillas (templates).


La generalidad es una propiedad que permite definir una clase o una funcin sin tener que especificar el tipo de todos o alguno de sus miembros. Esta propiedad no es imprescindible en un lenguaje de programacin orientado a objetos y ni siquiera es una de sus caractersticas. Esta caracterstica del C++ apareci mucho ms tarde que el resto del lenguaje, al final de la dcada de los ochenta. Esta generalidad se alcanza con las plantillas (templates). La utilidad principal de este tipo de clases o funciones es la de agrupar variables cuyo tipo no est predeterminado. As el funcionamiento de una pila, una cola, una lista, un conjunto, un diccionario o un array es el mismo independientemente del tipo de datos que almacene (int, long, double, char, u objetos de una clase definida por el usuario). En definitiva estas clases se definen independientemente del tipo de variables que vayan a contener y es el usuario de la clase el que debe indicar ese tipo en el momento de crear un objeto de esa clase. Plantillas de funciones Supngase que se quiere crear una funcin que devolviese el mnimo entre dos valores independientemente de su tipo (se supone que ambos tienen el mismo tipo). Se podra pensar en definir la funcin tantas veces como tipos de datos se puedan presentar (int, long, float, double, etc.). Aunque esto es posible, ste es uncaso ideal para aplicar plantillas de funciones. Esto se puede hacer de la siguiente manera:

// Declaracin de la plantilla de funcin. template <class T> T minimo( T a, T b); En ese caso con <classT> se est indicando que se trata de una plantilla cuyo parmetro va a ser el tipo T y que tanto el valor de retorno como cada uno de los dos argumentos va a ser de este tipo de dato T. En la definicin y declaracin de la plantilla puede ser que se necesite utilizar ms de un tipo de dato e incluido algn otro parmetro constante que pueda ser utilizado en las declaraciones. Por ejemplo, si hubiera que pasar dos tipos a la plantilla, se podra escribir: // Declaracin de la plantilla de funcin con dos tipos de datos template <class T1, class T2> void combinar(T1 a, T2 b); Podra darse el caso tambin de que alguno de los argumentos o el valor de retorno fuese de un tipo de dato constante y conocido. En ese caso se indicara explcitamente como en una funcin convencional. La definicin de la plantilla de funcin es como sigue: // Definicin de la plantilla de funcin template <class T> T minimo(T a, T b) {

11

if(a <= b) return a; else return b; } Puede pensarse que las plantillas y el polimorfismo son dos utilidades que se excluyen mutuamente. Aunque es verdad que el parecido entre ambas es grande, hay tambin algunas diferencias que pueden hacer necesarias ambas caractersticas. El polimorfismo necesita punteros y su generalidad se limita a jerarquas. Recurdese que el polimorfismo se basa en que en el momento de compilacin se desconoce a qu clase de la jerarqua va a apuntar un puntero que se ha definido como puntero a la clase base. Desde este punto de vista las plantillas pueden considerarse como una ampliacin del polimorfismo. Una desventaja de las plantillas es que tienden a crear un cdigo ejecutable grande porque se crean tantas versiones de las funciones como son necesarias.

12

1.8 La biblioteca STL.


La Biblioteca Estndar de Patrones, comnmente conocida en ingls por sus siglas STL (Standard Template Library) es una biblioteca de C++ que incluye la mayora de algoritmos y estructuras de datos que se suelen utilizar en Informtica. Bsicamente est compuesta de:  clases contenedoras, es decir, patrones (templates) que permiten almacenar objetos de muy diversos tipos.  algoritmos de uso frecuente.  iteradores, que nos permitirn recorrer los elementos incluidos en los contenedores.

Tambin incluye "objetos funcin", que son generalizaciones de funciones (clases tiles por el procesamiento que realizan y no por los datos que contienen), y "adaptadores", que modifican el interfaz de ciertos contenedores e iteradores de forma puedan ser manejados ms fcilmente. Esta biblioteca es genrica en tanto sus componentes estn altamente parametrizados, ya que casi todos son patrones, lo que permite su instancia con cualquier otro tipo de objeto, lo que hace que la STL se configure como una gran herramienta para la programacin de aplicaciones en C++. Los tipos de contenedores que nos podemos encontrar en la biblioteca son los siguientes:  Secuenciales: o Vectores: contienen elementos contiguos almacenados al estilo de un array o vector del lenguaje C++. o Listas: secuencias de elementos almacenados en una lista enlazada. o Deques: contenedores parecidos a los vectores, excepto que permiten inserciones y borrados en tiempo constante tanto al principio como al final.  Adaptadores: o Colas: contenedores que ofrecen la funcionalidad de listas "primero en entrar, primero en salir". o Pilas: contenedores asociados a listas "primero en entrar, ltimo en salir". o Colas con prioridad: en este caso, los elementos de la cola salen de ella de acuerdo con una prioridad (que se estableci en la insercin).  Asociativos. o Conjuntos de bits: contenedor para almacenar bits. o Mapas: almacenan pares "clave, objeto", es decir, almacenan objetos referidos mediante un identificador nico. o Multimapas: mapas que permiten claves duplicadas. o Conjuntos: conjuntos ordenados de objetos nicos. o Multiconjuntos: conjuntos ordenados de objetos que pueden estar duplicados.

13

Todas estas clases de objetos tienen la posibilidad de poder ser "recorridas" utilizan iteradores. Para ello, cada una de ellas tiene una subclase (o varias subclases) que nos permiten colocarnos en el primer elemento de un objeto, avanzar al siguiente elemento, ver el elemento (o modificarlo) y comprobar si ya hemos llegado hasta el final.

14

Preguntas de autoevaluacin.

15

TEMA 2 ARREGLOS.
Identificar y usar el tipo de estructura conocida como arreglo para dar solucin a necesidades de organizacin de datos que se presenten.

2.1 Arreglos lineales dinmicos.


Los arreglos (arrays) permiten agrupar datos usando un mismo identificador. Todos los elementos de un array son del mismo tipo, y para acceder a cada elemento se usan subndices. Sintaxis: <tipo><identificador>[<nm_elemen>][[<nm_elemen>]...]; Los valores para el nmero de elementos deben ser constantes, y se pueden usar tantas dimensiones como queramos, limitado slo por la memoria disponible. Cuando slo se usa una dimensin se suele hablar de listas o vectores, cuando se usan dos, de tablas. Ahora podemos ver que las cadenas de caracteres son un tipo especial de arrays. Se trata en realidad de arrays de una dimensin de objetos de tipo char. Los subndices son enteros, y pueden tomar valores desde 0 hasta <nmero de elementos>-1. En general C++ no verifica el mbito de los subndices. Si declaramos un array de 10 elementos, no obtendremos errores al acceder al elemento 11. Sin embargo, si asignamos valores a elementos fuera del mbito declarado, estaremos accediendo a zonas de memoria que pueden pertenecer a otras variables o incluso al cdigo ejecutable de nuestro programa, con consecuencias generalmente desastrosas. Ejemplo: int Tabla[10][10]; char DimensionN[4][15][6][8][11]; ... DimensionN[3][11][0][4][6] = DimensionN[0][12][5][3][1]; Tabla[0][0] += Tabla[9][9]; Si al iniciar un programa no se sabe el nmero de elementos del que va a constar el array, o no se quiere poner un lmite predetermiado, lo que hay que hacer es definir el array dinmicamente. Para hacer esto, primero se define un puntero, que sealar la direccin de memoria del primer elemento del array: tipo_de_elemento *nombre_de_array;

16

y luego se utiliza la funcin malloc (contenida en stdlib.h) para reservar memoria: nombre_de_array=(tipo_de_elemento *)malloc(tamao); donde tamao es el nmero de elementos del array por el tamao en bytes de cada elemento. La funcin malloc devuelve un puntero void, que indica la posicin del primer elemento. Antes de asignarlo a nuestro puntero, hay que convertir el puntero que devuelve el malloc al tipo de nuestro puntero (ya que no se pueden igualar punteros de distintos tipos).

17

2.2 Representacin de arreglos lineales en memoria

Esto es muy importante, y hay que tener mucho cuidado, por ejemplo: int Vector[10]; Crear un array con 10 enteros a los que accederemos como Vector[0] a Vector[9]. Como subndice podremos usar cualquier expresin entera. Los arrays pueden ser inicializados en la declaracin. Ejemplos: float R[10] = {2, 32, 4.6, 2, 1, 0.5, 3, 8, 0, 12}; float S[] = {2, 32, 4.6, 2, 1, 0.5, 3, 8, 0, 12}; int N[] = {1, 2, 3, 6}; int M[][3] = { 213, 32, 32, 32, 43, 32, 3, 43, 21}; char Mensaje[] = "Error de lectura"; char Saludo[] = {'H', 'o', 'l', 'a', 0}; En estos casos no es obligatorio especificar el tamao para la primera dimensin, como ocurre en los ejemplos de las lneas 2, 3, 4, 5 y 6. En estos casos la dimensin que queda indefinida se calcula a partir del nmero de elementos en la lista de valores iniciales. En el caso 2, el nmero de elementos es 10, ya que hay diez valores en la lista. En el caso 3, ser 4. En el caso 4, ser 3, ya que hay 9 valores, y la segunda dimensin es 3: 9/3=3. Y en el caso 5, el nmero de elementos es 17, 16 caracteres ms el cero de fin de cadena.

18

2.3 Operaciones con arreglos.


Ya hemos visto que se puede usar el operador de asignacin con arrays para asignar valores iniciales. El otro operador que tiene sentido con los arrays es sizeof. Aplicado a un array, el operador sizeof devuelve el tamao de todo el array en bytes. Podemos obtener el nmero de elementos dividiendo ese valor entre el tamao de uno de los elementos. #include <iostream> using namespace std; int main() { int array[231]; cout << "Nmero de elementos: " << sizeof(array)/sizeof(int) << endl; cout << "Nmero de elementos: " << sizeof(array)/sizeof(array[0]) << endl; cin.get(); return 0; } Las dos formas son vlidas, pero la segunda es, tal vez, ms general.

19

2.4 Arreglos dinmicos.


Si al iniciar un programa no se sabe el nmero de elementos del que va a constar el array, o no se quiere poner un lmite predetermiado, lo que hay que hacer es definir el array dinmicamente. Para hacer esto, primero se define un puntero, que sealar la direccin de memoria del primer elemento del array: tipo_de_elemento *nombre_de_array; y luego se utiliza la funcin malloc (contenida en stdlib.h) para reservar memoria: nombre_de_array=(tipo_de_elemento *)malloc(tamao); Donde tamao es el nmero de elementos del array por el tamao en bytes de cada elemento. La funcin malloc devuelve un puntero void, que indica la posicin del primer elemento. Antes de asignarlo a nuestro puntero, hay que convertir el puntero que devuelve el malloc al tipo de nuestro puntero (ya que no se pueden igualar punteros de distintos tipos). Para arrays bidimensionales, hay que hacerlo dimensin a dimensin; primero se define un puntero de punteros: int **mapa; Luego se reserva memoria para los punteros: mapa=(int **)malloc(sizeof(int *)*N1); y, por ltimo, para cada puntero se reserva memoria para los elementos: for(i1=0;i1<N1;i1++) mapa[i1]=(int *)malloc(sizeof(int)*N2); Ya se puede utilizar el array normalmente. Para arrays de ms de dos dimensiones, se hace de forma similar.

20

2.5 Punteros y arreglos de punteros.


Un puntero es una variable destinada a contener una direccin de memoria. Esta direccin generalmente corresponde a otra variable, decimos entonces que el puntero contiene la direccin de la variable o que apunta a sta. Sintaxis para declarar punteros: tipo * nombre_puntero; nombre_puntero es el identificador de la variable. El * es el operador de indireccin que nos indica que la variable es de tipo puntero. Tipo indica el tipo de la variable apuntada por el puntero (se lo denomina tipo base). Ejemplo: En la siguiente declaracin, p es un puntero a float, i es una variable tipo int y q es un puntero a int. int i, *q; float *p;

Punteros a estructura Sintaxis: struct tipo_estructura * nombre_estructura; tipo_estructura es un rtulo de una estructura. nombre_estructura es el identificador del puntero.

Ejemplo: Se crea un tipo de dato estructura con el nombre fecha. Luego se declara una variable de tipo estructura-fecha con el nombre hoy, y finalmente un puntero a estructura-fecha llamado F. struct fecha { int da; int mes; int anio;

21

}; struct fecha hoy; struct fecha * F;

F todava no apunta a una direccin vlida. Hacemos que F apunte a hoy, cargndolo con la direccin de esa variable tipo estructura-fecha. F = &hoy; Observe la presencia del operador &. Es necesario no confundir una estructura con un arreglo. En el caso de las estructuras, el nombre es el identificador de la variable y representa a la variable misma, no a su direccin. Por eso usamos el operador mencionado.

22

2.6 La clase VECTOR.


Aunque cada uno de los contenedores que ofrece la STL tienen caractersticas diferentes, en esta seccin presentaremos el contenedor vector. El contenedor vector permite almacenar cero o ms objetos del mismo tipo, pudiendo acceder a ellos individualmente mediante un ndice, es decir, acceso aleatorio. En este sentido, es una extensin del vector o array que ofrece C++, aunque en este caso el nmero de elementos de un objeto vector puede variar dinmicamente. La gestin de la memoria se hace de manera totalmente transparente al usuario. Se define como una clase patrn, lo que implica que puede albergar objetos de cualquier tipo. En cuanto a las operaciones ms frecuentes, ofrece un tiempo constante en insercin y borrados de elementos al final, y lineal al comienzo o en la mitad del vector. La declaracin ms comn de un objeto de tipo vector se realiza de la siguiente manera: vector<tipo> objeto donde tipo puede ser cualquier tipo o clase de los que ofrece C++, as como cualquier otra clase implementada por un usuario. As, podramos declarar los siguientes vectores: vector<double> vectorReales; // De nmeros reales. vector<string> vectorCadenas; // De cadenas de caracteres. vector<MiClase> vectorObj; // Contendr objetos de una clase construida por un usuario Una declaracin: vector <int> vectorEnteros(10); Crea un vector de diez enteros. Si deseamos inicializarlo a algn valor en concreto, entonces aadimos un argumento ms al constructor: vector <int> vectorEnteros(10,-1) De manera general las funciones miembro y operadores manejados por vector ms utilizadas son:

23

Veamos un ejemplo. El siguiente programa muestra dos constructores simples: #include <iostream> #include <cassert> #include <vector> using namespace std; int main() { cout << "Demostrando los constructores ms simple del vector" << endl; vector<char> vector1, vector2(3, 'x'); assert (vector1.size() == 0); assert (vector2.size() == 3); assert (vector2[0] == 'x' && vector2[1] == 'x' && vector2[2] == 'x'); assert (vector2 == vector<char>(3, 'x') && vector2 != vector<char>(4, 'x')); cout << " --- Ok." << endl; return 0; }

24

Preguntas de autoevaluacin.

25

TEMA 3 LISTAS.
Identificar y usar el tipo de estructura conocida como lista para dar solucin a necesidades de organizacin de datos que se presenten.

3.1 Definicin de lista.


Una lista es un conjunto de elementos del mismo tipo. Una propiedad importante con la que se caracteriza a las listas es que su longitud puede aumentar o disminuir, segn se requiera. Es ms, podemos insertar o eliminar elementos en cualquier posicin de una lista. Las listas se pueden implementar de 2 modos distintos: mediante vectores o mediante estructuras dinmicas enlazadas por apuntadores. El trabajo de listas con vectores tiene una limitante: las listas tienen una longitud variable (dinmicas) y los vectores tienen longitud esttica. No podramos definir un arreglo de tamao N donde solamente utilicemos los primero N-m cajones. O viceversa, declarar un arreglo demasiado pequeo para nuestras necesidades. Esto es el porqu de las estructuras dinmicas de datos. La forma ms simple de estructura dinmica es la lista. En esta forma los nodos se organizan de modo que cada uno apunta al siguiente, y el ltimo no apunta a nada, es decir, el puntero del nodo siguiente vale NULL. En las listas abiertas existe un nodo especial: el primero. Normalmente diremos que nuestra lista es un puntero a ese primer nodo y llamaremos a ese nodo la cabeza de la lista. Eso es porque mediante ese nico puntero podemos acceder a toda la lista. Cuando el puntero que usamos para acceder a la lista vale NULL, diremos que la lista est vaca. El nodo tpico para construir listas tiene esta forma:

En el ejemplo, cada elemento de la lista slo contiene un dato de tipo entero, pero en la prctica no hay lmite en cuanto a la complejidad de los datos a almacenar.

26

3.2 Asignacin de memoria a la lista.


Normalmente se definen varios tipos que facilitan el manejo de las listas, la declaracin de tipos puede tener una forma en memoria parecida a esta:

Dnde: tipoNodo es el tipo para declarar nodos. pNodo es el tipo para declarar punteros a un nodo. Lista es el tipo para declarar listas. Como puede verse, un puntero a un nodo y una lista son la misma cosa. En realidad, cualquier puntero a un nodo es una lista, cuyo primer elemento es el nodo apuntado, por ejemplo:

Es muy importante que un programa nunca pierda el valor del puntero al primer elemento, ya que si no existe ninguna copia de ese valor, y se pierde, ser imposible acceder al nodo y no podremos liberar el espacio de memoria que ocupa.

27

3.3 La clase lista de STL.

El contenedor de decencia LIST cuenta con una eficiente combinacin para las operaciones de insercin y eliminacin en cualquier posicin del contenedor. La clase LIST se implementa como una lista doblemente enlazada: cada nodo en una lista contiene un apuntador al nodo anterior y al nodo siguiente de esta lista. Esto permite a la clase LIST soportar iteradotes bidireccionales que permiten que el contenedor se recorra tanto hacia delante como hacia atrs. Adems de las funciones miembro de todos los contenedores de la STL y de las funciones miembro comunes de todos los contenedores de secuencia, la clase LIST cuenta con otras ocho funciones miembro: splice: elimina elementos de una estructura y los almacena en otra, utiliza distintos formatos. remove: elimina el elemento especificado de la lista. unique: elimina elementos duplicados de una lista. merge: elimina elementos de una estructura y los almacena en otra, de manera ordenada. reverse: invierte los elementos de una lista. sort: ordena los elementos de la lista. push_front: inserta un elemento en la parte frontal de la lista. pop_front: elimina un elemento de la parte frontal de la lista.

28

3.4 Iteradores para la clase lista.


Un puntero a un nodo y una lista son la misma cosa. En realidad, cualquier puntero a un nodo es una lista, cuyo primer elemento es el nodo apuntado. Gracias a los iteradores tendremos un pequeo repertorio de operaciones bsicas que se pueden realizar: y Aadir o insertar elementos. y Buscar o localizar elementos. y Borrar elementos. y Moverse a travs de una lista, anterior, siguiente, primero. Cada una de estas operaciones tendr varios casos especiales, por ejemplo, no ser lo mismo insertar un nodo en una lista vaca, o al principio de una lista no vaca, o la final, o en una posicin intermedia. A continuacin se describen algunos programas de ejmplo con iteradores.

List::const_iterator (STL/CLR)
En esta aplicacin se declara el uso de un iterador constante y es el iterador quien se encarga de mostrar la estructura de la lista.Definir un tipo de un iterador constante para la secuencia controlada.
typedef T2 const_iterator;
Se describe un objeto de tipo no especificado T2 que servira como un iterador de acceso aleatorio constante para la secuencia controlada.

// cliext_list_const_iterator.cpp // compile with: /clr #include <cliext/list> int main() { cliext::list<wchar_t> c1; c1.push_back(L'a'); c1.push_back(L'b'); c1.push_back(L'c'); // display contents " a b c" cliext::list<wchar_t>::const_iterator cit = c1.begin(); for (; cit != c1.end(); ++cit) System::Console::Write(" {0}", *cit); System::Console::WriteLine(); return (0); }

El Resultado debera ser el siguiente: a b c

29

List::const_reference (STL/CLR) En este ejercicio se hace uso de un tipo constante que toma el lugar del iterador para mostrar la estructura de la lista. El tipo de una constante referencia a un elemento.
typedef value_type% const_reference; // cliext_list_const_reference.cpp // compile with: /clr #include <cliext/list> int main() { cliext::list<wchar_t> c1; c1.push_back(L'a'); c1.push_back(L'b'); c1.push_back(L'c'); // display initial contents " a b c" cliext::list<wchar_t>::const_iterator cit = c1.begin(); for (; cit != c1.end(); ++cit) { // get a const reference to an element cliext::list<wchar_t>::const_reference cref = *cit; System::Console::Write(" {0}", cref); } System::Console::WriteLine(); return (0); }

El resultado debera ser:

abc

List::iterator (STL/CLR)
En este ejercicio el iterador es declarado pero noten como tiene acceso aleatorio directo a los elementos de la lista.El tipo de un iterador para la secuencia controlada. typedef T1 iterator; El tipo describe un objeto de tipo no especificado T1 que sirve como un iterador de acceso aleatorio para la secuencia controlada.
// cliext_list_iterator.cpp // compile with: /clr #include <cliext/list> int main() { cliext::list<wchar_t> c1; c1.push_back(L'a');

30

c1.push_back(L'b'); c1.push_back(L'c'); // display contents " a b c" cliext::list<wchar_t>::iterator it = c1.begin(); for (; it != c1.end(); ++it) System::Console::Write(" {0}", *it); System::Console::WriteLine(); // alter first element and redisplay it = c1.begin(); *it = L'x'; for (; it != c1.end(); ++it) System::Console::Write(" {0}", *it); System::Console::WriteLine(); return (0); }

Resultado:

a b c x b c

31

3.5 Construccin de listas.


Partimos de un nodo a insertar, con un puntero que apunte a l, y de una lista, en este caso no vaca:

El proceso sigue siendo muy sencillo: 1. Hacemos que nodo->siguiente apunte a Lista. 2. Hacemos que Lista apunte a nodo.

En algunos casos partimos de una lista no vaca:

El proceso en este caso tampoco es excesivamente complicado: 1. Necesitamos un puntero que seale al ltimo elemento de la lista. La manera de conseguirlo es empezar por el primero y avanzar hasta que el nodo que tenga como siguiente el valor NULL. 2. Hacer que nodo->siguiente sea NULL. 3. Hacer que ultimo->siguiente sea nodo.

32

3.6 Algoritmos genricos sobre colecciones de STL.


La librera estndar proveeherramientasquefacilitanla programacion.Eselcasodelos string,quepermitenevitarlosproblemasmas clsicos conlascadenasdecaracteres alaC . strings1( Primera ); strings2= Segunda ; strings3=s1+ y +s2; s3.append( y aun mas ); La librer a estndar generico,implementadocomo cdigo C++. tambin provee,fueradetodaclase/patron, cdigo funcionespatrones.Sonabstraccionesdefuncionesrecurrentesen

Esta funcion copiatodosloselementosdentrodeunarreglo,dentrodeunoslimites(dadosen trminos deapuntadores),haciaotroarreglo.Seahorraescribirciclos! Como estaimplementadocomo template,sepuedeusar cualquiertipodeapuntador.

33

Preguntas de autoevaluacin.

34

TEMA 4 PILAS.
Identificar y usar el tipo de estructura conocida como pila para dar solucin a necesidades de organizacin de datos que se presenten.

4.1 Definicin de pilas.


Una pila es un tipo especial de lista abierta en la que slo se pueden insertar y eliminar nodos en uno de los extremos de la lista. Estas operaciones seconocen como "push" y "pop", respectivamente "empujar" y "tirar". Adems, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el nodo ledo. Estas caractersticas implican un comportamiento de lista LIFO (Last In First Out), el ltimo en entrar es el primero en salir. La ms sencilla de las estructuras dinmicas de datos es la pila, las pilas son utilizadas sobre todo por los sistemas operativos y los controladores de los lenguajes de alto nivel. Una pila es dinmica: crece y encoge a medida que es necesario. Una manera de ver esta estructura es pensar en las pilas como si fuese una pila de bandejas de un autoservicio. Las bandejas se ponen en la pila por arriba, la bandeja de arriba se la lleva de la pila un cliente que este en la cola. Este escenario se denomina modelo del ltimo en llegar-primero en salir: la ltima bandeja que se ponga en la pila ser la primera que se lleven.

35

4.2 Implementacin de pilas.

El nodo tpico para construir pilas es el siguiente:

Los tipos que se definen normalmente para manejar pilas son casi los mismos que para manejar listas, tan slo se cambian algunos nombres de la siguiente manera:

Dnde: tipoNodo es el tipo para declarar nodos, evidentemente. pNodo es el tipo para declarar punteros a un nodo. Pila es el tipo para declarar pilas. As una manera grfica de ver la estructura sera:

Es evidente, a la vista del grfico, que una pila es una lista abierta. As que sigue siendo muy importante que un programa nunca pierda el valor del puntero al primer elemento, igual que pasa con las listas abiertas.

36

4.3 La clase STACK de STL


La clase STACK permite insertar a, y eliminar de, la estructura de datos subyacente en un extremo. Una pila puede implementarse con cualquiera de los contenedores de secuencia; vector, list y deque. De manera predeterminada, una pila se implementa con un deque. Las operaciones de la pila son: push para insertar un elemento en la parte superior, pop para eliminar el elemento de la pila, top para obtener una referencia al elemento de la pila, empty para determinar si la pila se encuentra vaca o no y size para obtener el nmero de elementos de la pila. Para poder hacer uso de la clase STACK es necesario incluir el archivo de encabezado <stack>, por ejemplo, el siguiente codigo crea tres pilas de enteros utilizando cada uno de los contenedores de secuencia de la STL como estructura de datos subyacente para representar al adaptador STACK. // Programa de prueba para el adaptador stack de la Biblioteca estndar. #include <iostream> using std::cout; using std::endl; #include <stack> // definicin del adaptador stack #include <vector> // definicin de la plantilla de clase vector #include <list> // definicin de la plantilla de clase list // prototipo de la plantilla de funcin sacarElementos template< class T > void sacarElementos( T &stackRef ); int main() { // pila con deque subyacente predeterminado std::stack< int > intDequePila; // pila con vector subyacente std::stack< int, std::vector< int >> intVectorPila; // pila con lista subyacente std::stack< int, std::list< int >> intListaPila; // meter los valores 0-9 en cada pila for ( int i = 0; i < 10; ++i ) {

37

intDequePila.push( i ); intVectorPila.push( i ); intListaPila.push( i ); } // fin de instruccin for // mostrar y eliminar elementos de cada pila cout << "Sacando de intDequePila: "; sacarElementos( intDequePila ); cout << "\nSacando de intVectorPila: "; sacarElementos( intVectorPila ); cout << "\nSacando de intListaPila: "; sacarElementos( intListaPila ); cout << endl; return 0; } // fin de main // sacar elementos del objeto pila al que hace referencia stackRef template< class T > void sacarElementos( T &stackRef ) { while ( !stackRef.empty() ) { cout << stackRef.top() << ' '; // ver elemento superior stackRef.pop(); // eliminar elemento superior } // fin de instruccin while } // fin de la funcin sacarElementos

38

4.4 Iteradores para la clase Stack.


El termino iterar significa (en palabras sencillas) el mtodo o forma que se usa para poder navegar sobre los elementos de una lista especfica. Luego, un iterador es como una especie de "puntero especial" que nos permite leer o escribir valores sobre cada uno de los elementos en una lista. Los iteradores pueden ser comparados con los ndices que se emplean para leer o escribir valores sobre los elementos de una lista. Igual a lo que sucede con los tipos de datos dentro de un arreglo primitivo en donde para leer o escribir valores sobre los elementos se tiene que prestar atencin al tipo de dato, un iterador tiene que ser del tipo de dato que posee la lista. En ese sentido, si tenemos por ejemplo un vector que posee datos de tipo entero (int) entonces el iterador tendr que ser de tipo entero; si por el contrario se tiene un vector cuyos datos son del tipo cadena (string) entonces el iterador tiene que ser del tipo cadena. La sintaxis general para la declaracin de un iterador es: NombrePlantilla<tipo>::iterator varid; Donde, NombrePlantilla Es el nombre de una STL tipo Es el tipo usado para la plantilla ::iterator Es el mtodo para obtener el iterador varid Es el nombre de la variable

La forma de los programas es igual a la que ya se ha visto por lo que slo se expondr la parte inicial donde se hace referencia a la definicin de la pila.
#include <iostream> #include <stack> using namespace std; main() { stack < int> s; s.push(1); s.push(2); s.push(3); while(!s.empty()){ cout<<" s.pop(); } cout<<" "; }

" <<s.top()<<endl;

system("pause");

39

4.5Construccin de Pilas.
Supongamos que queremos construir una pila para almacenar nmeros enteros. 1. Creamos un nodo para el valor que colocaremos en la pila. 2. Hacemos que nodo->siguiente apunte a Pila. 3. Hacemos que Pila apunte a nodo.

Algoritmo de la funcin "pop": 1. Hacemos que nodo apunte al primer elemento de la pila, es decir, a Pila. 2. Asignamos a Pila la direccin del segundo nodo de la pila: Pila->siguiente. 3. Guardamos el contenido del nodo para devolverlo como retorno. 4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar.

40

Tambin puede hacerse uso de clases. Las clases para pilas son versiones simplificadas de las mismas clases que usamos para listas. Para empezar, necesitaremos dos clases, una para nodo y otra para pila. Adems la clase para nodo debe ser amiga de la clase pila, ya que sta debe acceder a los miembros privados de nodo.

41

Preguntas de autoevaluacin.

42

TEMA 5 COLAS.
Identificar y usar el tipo de estructura conocida como cola para dar solucin a necesidades de organizacin de datos que se presenten.

5.1 Definicin de colas.


Una cola es un tipo especial de lista abierta en la que slo se puede insertar nodos en uno de los extremos de la lista y slo se pueden eliminar nodos en el otro. Adems, como sucede con las pilas, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el nodo ledo. Este tipo de lista es conocido como lista FIFO (First In First Out), el primero en entrar es el primero en salir. Un ejemplo cotidiano es una cola para comprar, por ejemplo, las entradas del cine. Los nuevos compradores slo pueden colocarse al final de la cola, y slo el primero de la cola puede comprar la entrada.

43

5.2 Construccin de colas.

El nodo tpico para construir colas es el mismo para la construccin de listas y pilas:

Los tipos que se definen normalmente para manejar colas son casi los mismos que para manejar listas y pilas, tan slo se cambian algunos nombres:

Dnde: tipoNodo es el tipo para declarar nodos. pNodo es el tipo para declarar punteros a un nodo. Cola es el tipo para declarar colas. De manera similar a las pilas, una cola se puede representar grficamente como:

Es evidente que una cola es una lista abierta. As que sigue siendo muy importante que un programa nunca pierda el valor del puntero al primer elemento, igual que pasa con las listas abiertas. Adems, debido al funcionamiento de las colas, tambin se debe mantener un puntero para el ltimo elemento de la cola, que ser el punto donde insertemos nuevos nodos. Teniendo en cuenta que las lecturas y escrituras en una cola se hacen siempre en extremos distintos, lo ms fcil ser insertar nodos por el final, a continuacin del nodo que no tiene nodo siguiente, y leerlos desde el principio, hay que recordar que leer un nodo implica eliminarlo de la cola.

44

5.3 La clase queue de STL.


La clase QUEUE permite inserciones en la parte final de la estructura de datos subyacentes y eliminaciones en la parte inicial de la misma. Una cola puede implementarse con la estructura de datos list o deque de la STL, de manera predeterminada una cola se implementa con deque. Las operaciones comunes de un adaptador queue son push para insertar un elemento en su parte final, pop para eliminar el elemento en la parte inicial de la cola, front para obtener una referencia al primer elemento de la cola, back para obtener una referencia al ltimo elemento de la cola, empty para determinar si la cola est o no vaca y size para obtener el nmero de elementos de la cola. El archivo de encabezado <queue> debe incluirse para poder utilizar esta clase. Por ejemplo, el siguiente codigo muestra el uso de la clase queue. // Programa de prueba para el adaptador queue de la Biblioteca estndar. #include <iostream> using std::cout; using std::endl; #include <queue> // definicin del adaptador queue int main() { std::queue< double >valores; // meter elementos en la cola valores valores.push( 3.2 ); valores.push( 9.8 ); valores.push( 5.4 ); cout << "Sacando de valores: "; while ( !valores.empty() ) { cout << valores.front() << ' '; // ver elemento inicial valores.pop(); // eliminar elemento } // fin de instruccin while cout << endl; return 0; } // fin de main

45

5.4 Iteradores para la clase Queue.


Supngase que construimos una cola para almacenar nmeros enteros. 1. Creamos un nodo para el valor que colocaremos en la cola. 2. Hacemos que nodo->siguiente apunte a NULL. 3. Si "ultimo" no es NULL, hacemos que ultimo->siguiente apunte a nodo. 4. Actualizamos "ultimo" haciendo que apunte a nodo. 5. Si "primero" es NULL, hacemos que apunte a nodo. void Anadir(pNodo *primero, pNodo *ultimo, int v) { pNodo nuevo; /* Crear un nodo nuevo */ nuevo = (pNodo)malloc(sizeof(tipoNodo)); nuevo->valor = v; /* Este ser el ltimo nodo, no debe tener siguiente */ nuevo->siguiente = NULL; /* Si la cola no estaba vaca, aadimos el nuevo a continuacin de ultimo */ if(*ultimo) (*ultimo)->siguiente = nuevo; /* Ahora, el ltimo elemento de la cola es el nuevo nodo */ *ultimo = nuevo; /* Si primero es NULL, la cola estaba vaca, ahora primero apuntar tambin al nuevo nodo */ if(!*primero) *primero = nuevo; }

Algoritmo de la funcin "leer": 1. Hacemos que nodo apunte al primer elemento de la cola, es decir a primero. 2. Asignamos a primero la direccin del segundo nodo de la cola: primero->siguiente. 3. Guardamos el contenido del nodo para devolverlo como retorno. 4. Liberamos la memoria asignada al primer nodo, el que queremos eliminar. 5. Si primero es NULL, haremos que ltimo tambin apunte a NULL, ya que la cola habr quedado vaca. int Leer(pNodo *primero, pNodo *ultimo) { pNodo nodo; /* variable auxiliar para manipular nodo */ int v; /* variable auxiliar para retorno */ /* Nodo apunta al primer elemento de la pila */ nodo = *primero;

46

if(!nodo) return 0; /* Si no hay nodos en la pila retornamos 0 */ /* Asignamos a primero la direccin del segundo nodo */ *primero = nodo->siguiente; /* Guardamos el valor de retorno */ v = nodo->valor; /* Borrar el nodo */ free(nodo); /* Si la cola qued vaca, ultimo debe ser NULL tambin*/ if(!*primero) *ultimo = NULL; return v; }

47

Preguntas de autoevaluacin.

48

TEMA 6 ARBOLES.
Identificar y usar el tipo de estructura conocida como rbol para dar solucin a necesidades de organizacin de datos que se presenten.

6.1 Definicin de rbol.


Un rbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios nodos. Tambin se suele dar una definicin recursiva: un rbol es una estructura en compuesta por un dato y varios rboles, la forma grfica se puede apreciar como sigue:

En relacin con nodos se pueden definir conceptos como:  Nodo hijo: cualquiera de los nodos apuntados por uno de los nodos del rbol. En el ejemplo, 'L' y 'M' son hijos de 'G'.  Nodo padre: nodo que contiene un puntero al nodo actual. En el ejemplo, el nodo 'A' es padre de 'B', 'C' y 'D'. En cuanto a la posicin dentro del rbol, encontramos: y y Nodo raz: nodo que no tiene padre. Este es el nodo que usaremos para referirnos al rbol. En el ejemplo, ese nodo es el 'A'. Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N' y 'O'.

49

Nodo rama: aunque esta definicin apenas la usaremos, estos son los nodos que no pertenecen a ninguna de las dos categoras anteriores. En el ejemplo: 'B', 'C', 'D', 'E', 'G' y 'J'.

Un rbol en el que en cada nodo o bien todos o ninguno de los hijos existe, se llama rbol completo. Los rboles se parecen al resto de las estructuras que hemos visto: dado un nodo cualquiera de la estructura, podemos considerarlo como una estructura independiente, es decir, un nodo cualquiera puede ser considerado como la raz de un rbol completo.

50

6.2 rboles binarios.


Los rboles de orden dos son bastante especiales, de hecho les dedicaremos varios captulos. Estos rboles se conocen tambin como rboles binarios. Frecuentemente, aunque no es estrictamente necesario, para hacer ms fcil el moverse a travs del rbol, se aade un puntero a cada nodo que apunte al nodo padre. De este modo podremos avanzar en direccin a la raz, y no slo hacia las hojas. Un rbol binario esta vaco o consta de un nodo denominado raz junto con dos rboles binarios llamados subrbol izquierdo y subrbol derecho de la raz. Adems de que los rboles binarios se emplean para bsquedas, la recuperacin de informacin es una de las aplicaciones ms importantes, y para ello existen los rboles de bsqueda binaria.

51

6.3 Representacin de rboles binarios en memoria.


La nica manera de construir un rbol binario con un nodo consiste en hacer que el nodo sea su raz y que estn vacos sus subrboles izquierdo y derecho (representan un apuntador a NULL), esto significa que se trata de un rbol ordinario. Con dos nodos en el rbol, uno de ellos ser la raz y el otro estar en un subrbol. As, uno de los subrboles de la izquierda o derecha debe estar vaco y el otro contendr un nodo. De ah que haya dos rboles binarios diferentes con dos nodos.

En el caso de un rbol binario con tres nodos, uno de estos ser la raz y los otros dos se dividirn entre los subrboles de la izquierda y derecha en una de las siguientes formas: 2 + 0, 1 + 1 y 0 + 2.

Como hay dos rboles binarios con dos nodos y solo un rbol vaco, en el primer caso da dos rboles binarios. El tercero tambin lo hace. En el segundo caso, los subrboles izquierdo y derecho tienen un nodo, y solo hay un rbol binario con un nodo y por eso hay uno en el segundo. As pues, en total existen cinco rboles binarios con tres nodos. Un rbol binario tiene una representacin natural en el almacenamiento de listas ligadas.

52

6.4Recorrido de rboles.
El modo evidente de moverse a travs de las ramas de un rbol es siguiendo los punteros, del mismo modo en que nos movamos a travs de las listas. Esos recorridos dependen en gran medida del tipo y propsito del rbol, pero hay ciertos recorridos que usaremos frecuentemente. Se trata de aquellos recorridos que incluyen todo el rbol. Hay tres formas de recorrer un rbol completo, y las tres se suelen implementar mediante recursividad. En los tres casos se sigue siempre a partir de cada nodo todas las ramas una por una. Supongamos que tenemos un rbol de orden tres, y queremos recorrerlo por completo. Partiremos del nodo raz: RecorrerArbol(raiz); La funcin RecorrerArbol, aplicando recursividad, ser tan sencilla como invocar de nuevo a la funcin RecorrerArbol para cada una de las ramas: void RecorrerArbol(Arbol a) { if(a == NULL) return; RecorrerArbol(a->rama[0]); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); } Lo que diferencia los distintos mtodos de recorrer el rbol no es el sistema de hacerlo, sino el momento que elegimos para procesar el valor de cada nodo con relacin a los recorridos de cada una de las ramas.

Los tres tipos son:

53

Pre-orden: En este tipo de recorrido, el valor del nodo se procesa antes de recorrer las ramas: void PreOrden(Arbol a) { if(a == NULL) return; Procesar(dato); RecorrerArbol(a->rama[0]); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); } Si seguimos el rbol del ejemplo en pre-orden, y el proceso de los datos es sencillamente mostrarlos por pantalla, obtendremos algo as: ABEKFCGLMDHIJNO In-orden: En este tipo de recorrido, el valor del nodo se procesa despus de recorrer la primera rama y antes de recorrer la ltima. Esto tiene ms sentido en el caso de rboles binarios, y tambin cuando existen ORDEN-1 datos, en cuyo caso procesaremos cada dato entre el recorrido de cada dos ramas (este es el caso de los rboles-b): void InOrden(Arbol a) { if(a == NULL) return; RecorrerArbol(a->rama[0]); Procesar(dato); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); } Si seguimos el rbol del ejemplo en in-orden, y el proceso de los datos es sencillamente mostrarlos por pantalla, obtendremos algo as: KEBFALGMCHDINJO

Post-orden: En este tipo de recorrido, el valor del nodo se procesa despus de recorrer todas las ramas: void PostOrden(Arbol a) { if(a == NULL) return; RecorrerArbol(a->rama[0]); RecorrerArbol(a->rama[1]); RecorrerArbol(a->rama[2]); Procesar(dato); } Si seguimos el rbol del ejemplo en post-orden, y el proceso de los datos es sencillamente mostrarlos por pantalla, obtendremos algo as: K E F B L M G C H I N O J D A

54

6.5 Arboles binarios de bsqueda.


Se trata de rboles de orden 2 en los que se cumple que para cada nodo, el valor del nodo raz del subrbol izquierdo es menor que el valor del nodo raz y que el valor del nodo raz del subrbol derecho es mayor que el valor del nodo raz.

55

6.6Bsqueda e insercin de rboles binarios de bsqueda.


Buscar un elemento. Partiendo siempre del nodo raz, el modo de buscar un elemento se define de forma recursiva como:  Si el rbol est vaco, terminamos la bsqueda: el elemento no est en el rbol.  Si el valor del nodo raz es igual que el del elemento que buscamos, terminamos la bsqueda con xito.  Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos la bsqueda en el rbol izquierdo.

 Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la
bsqueda en el rbol derecho. El valor de retorno de una funcin de bsqueda en un ABB puede ser un puntero al nodo encontrado, o NULL, si no se ha encontrado. Insertar un elemento. Para insertar un elemento nos basamos en el algoritmo de bsqueda. Si el elemento est en el rbol no lo insertaremos. Si no lo est, lo insertaremos a continuacin del ltimo nodo visitado. Para ello, se necesita un puntero auxiliar para conservar una referencia al padre del nodo raz actual. El valor inicial para ese puntero es NULL. y y Padre = NULL nodo = Raiz

y Bucle: mientras actual no sea un rbol vaco o hasta que se encuentre el elemento. o Si el valor del nodo raz es mayor que el elemento que buscamos, continuaremos
la bsqueda en el rbol izquierdo: Padre=nodo, nodo=nodo->izquierdo o Si el valor del nodo raz es menor que el elemento que buscamos, continuaremos la bsqueda en el rbol derecho: Padre=nodo, nodo=nodo->derecho. Si nodo no es NULL, el elemento est en el rbol, por lo tanto salimos. Si Padre es NULL, el rbol estaba vaco, por lo tanto, el nuevo rbol slo contendr el nuevo elemento, que ser la raz del rbol. Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un nuevo rbol izquierdo de Padre. Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un nuevo rbol derecho de Padre.

y y y y

Este modo de actuar asegura que el rbol sigue siendo ABB.

56

6.7rboles degenerados.
Los rboles binarios de bsqueda tienen un gran inconveniente. Por ejemplo, supongamos que creamos un ABB a partir de una lista de valores ordenada: 2, 4, 5, 8, 9, 12 Difcilmente podremos llamar a la estructura resultante un rbol:

Esto es lo que llamamos un rbol binario de bsqueda degenerado, y el rbol AVL, es la estructura que resuelve este problema, generando rboles de bsqueda equilibrados.

57

6.8Aplicaciones de rboles.
Un ejemplo de estructura en rbol es el sistema de directorios y ficheros de un sistema operativo. Aunque en este caso se trata de rboles con nodos de dos tipos, nodos directorio y nodos archivo, podramos considerar que los nodos hoja son archivos y los nodos rama son directorios. Otro ejemplo podra ser la tabla de contenido de un libro, por ejemplo de este mismo manual, dividido en captulos, y cada uno de ellos en subcaptulos. Aunque el libro sea algo lineal, como una lista, en el que cada captulo sigue al anterior, tambin es posible acceder a cualquier punto de l a travs de la tabla de contenido. Tambin se suelen organizar en forma de rbol los organigramas de mando en empresas o en el ejrcito, y los rboles genealgicos.

58

Preguntas de autoevaluacin.

59

CONCLUSIONES
Las estructuras de datos y algoritmos que faciliten su comprensin y desarrollo, constituyen elementos bsicos en el almacenamiento y tratamiento de la informacin. El entendimiento y conocimiento del concepto de estructuras y sus representaciones y mtodos que desembocan en el desarrollo de programas constituyen un previo indispensable para introducirse en el mbito de la programacin.

60

BIBLIOGRAFA
Como programar C++ Deitel & Deitel 4 Ed. Pearson/Prentice Hall Desarrollo de algoritmos y sus aplicaciones en Basic, Cobol y C. Guillermo Correa Uribe. 3 Ed. McGraw Hill. Estructuras de datos y algoritmos. Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman Addison-Wesley Iberoamericana. Estructuras de datos. Algoritmos, abstraccin y objetos. Luis Joyanes Aguilar, Ignacio Zahonero Martnez. McGraw Hill. Guia de Autoenseanza C++ Herbert Schildt McGraw Hill. Manual de Estructuras dinmicas de datos. Salvador Pozo.

61

You might also like