estructura de datos

62
  ESTRUCTURA DE DATOS Cuadernillo El alumno aplicará las clases de la biblioteca estándar STL del lenguaje C++ y será capaz de manejar l as estructuras de datos dinámicas, para la elaboración de programas utilizando la programación orientada a objetos. L.I. Octavio Molina Aguilar 13/07/2011

Upload: octavio-molina-aguilar

Post on 06-Jul-2015

1.827 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 1/62

 

 

ESTRUCTURA DEDATOSCuadernillo

El alumno aplicará las clases de la biblioteca estándar STLdel lenguaje C++ y será capaz de manejar las estructurasde datos dinámicas, para la elaboración de programasutilizando la programación orientada a objetos.

L.I. Octavio Molina Aguilar

13/07/2011

Page 2: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 2/62

 

 

INTRODUCCIÓN. ............................................................................................................................. 3

TEMA 1 .......................................................................................................................................... 4

ANTECEDENTES. ............................................................................................................................. 4

1.1 Introducción a la orientación a objetos. ................................................................................ 4

1.2 Tipos de datos abstractos. .................................................................................................... 6

1.3 Definición de estructuras de datos. ......................... ................................ ...................... ........ 7

1.4 Colecciones genéricas 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 autoevaluación. .................................................................................................. 15TEMA 2 ........................................................................................................................................ 16

ARREGLOS. ................................................................................................................................... 16

2.1 Arreglos lineales dinámicos. .......................... ................................ ...................... ................ 16

2.2 Representación de arreglos lineales en memoria ............................ ....................... ............. 18

2.3 Operaciones con arreglos. .................................................................................................. 19

2.4 Arreglos dinámicos. ............................................................................................................ 20

2.5 Punteros y arreglos de punteros. ........................................................................................ 21

2.6 La clase VECTOR. ................................................................................................................ 23

Preguntas de autoevaluación. .................................................................................................. 25

TEMA 3 ........................................................................................................................................ 26

LISTAS. ......................................................................................................................................... 26

3.1 Definición de lista. .............................................................................................................. 26

3.2 Asignación de memoria a la lista. ........................................................................................ 27

3.3 La clase lista de STL. ............................................................................................................ 28

3.4 Iteradores para la clase lista................................................................................................ 29

3.5 Construcción de listas. ........................................................................................................ 32

3.6 Algoritmos genéricos sobre colecciones de STL. ............................... ...................... ............. 33

Preguntas de autoevaluación. .................................................................................................. 34

TEMA 4 ........................................................................................................................................ 35

PILAS. ........................................................................................................................................... 35

Page 3: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 3/62

 

 

4.1 Definición de pilas. ............................................................................................................. 35

4.2 Implementación de pilas. ........................ ................................ ....................... ..................... 36

4.3 La clase STACK de STL ......................................................................................................... 37

4.4 Iteradores para la clase Stack. ............................................................................................. 39

4.5 Construcción de Pilas. ......................................................................................................... 40

Preguntas de autoevaluación. .................................................................................................. 42

TEMA 5 ........................................................................................................................................ 43

COLAS. ......................................................................................................................................... 43

5.1 Definición de colas. ............................................................................................................. 43

5.2 Construcción de colas. ........................................................................................................ 44

5.3 La clase queue de STL. ........................................................................................................ 45

5.4 Iteradores para la clase Queue. .......................................................................................... 46Preguntas de autoevaluación. .................................................................................................. 48

TEMA 6 ........................................................................................................................................ 49

ARBOLES. ..................................................................................................................................... 49

6.1 Definición de árbol. ............................................................................................................ 49

6.2 Árboles binarios. ................................................................................................................. 51

6.3 Representación de árboles binarios en memoria. ............................................................... 52

6.4 Recorrido de árboles........................................................................................................... 53

6.5 Arboles binarios de búsqueda. ............................................................................................ 55

6.6 Búsqueda e inserción de árboles binarios de búsqueda. ............................................ ......... 56

6.7 Árboles degenerados. ......................................................................................................... 57

6.8 Aplicaciones de árboles. ..................................................................................................... 58

Preguntas de autoevaluación. .................................................................................................. 59

CONCLUSIONES ............................................................................................................................ 60

BIBLIOGRAFÍA .............................................................................................................................. 61

Page 4: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 4/62

 

 

INTRODUCCIÓN. 

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 características de

un compilador en cuanto a palabras reservadas del lenguaje, comportamiento de los elementosque 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 homologación o etiqueta de calidad de un compilador.

Todos los compiladores incluyen, además del ANSI, ciertas características no ANSI, por ejemplo

librerías para gráficos. Pero mientras no usemos ninguna de esas características, sabremos que

nuestros programas son transportables, es decir, que podrán ejecutarse en cualquier ordenador y

con cualquier sistema operativo.

Junto con los compiladores de C y C++, se incluyen ciertos ficheros llamados librerías. Las librerías

contienen el código objeto de muchos programas que permiten hacer cosas comunes, como leer

el teclado, escribir en la pantalla, manejar números, realizar funciones matemáticas, etc. Las

librerías están clasificadas por el tipo de trabajos que hacen, hay librerías de entrada y salida,

matemáticas, de manejo de memoria, de manejo de textos, etc.

Hay un conjunto de librerías muy especiales, que se incluyen con todos los compiladores de C y de

C++. Son las librerías ANSI o estándar. Pero también hay librerías no estándar, y dentro de estas las

hay públicas y comerciales. En este nos centraremos en la librería estándar STL.

Page 5: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 5/62

 

 4

TEMA 1

ANTECEDENTES.

Presentar a los alumnos las estructuras de datos básicas y su transformación en estructuras más

complejas. Se pretende que los alumnos puedan definir o elegir estructuras adecuadas para la

resolución de problemas específicos de la vida real apoyados en las técnicas computacionales.

1.1 Introducción a la orient ación a objetos. 

La programación orientada a objetos (POO) es una nueva manera de enfocar la programación.

Desde sus comienzos, la programación ha estado gobernada por varias metodologías. En cada

punto crítico de la evolución de la programación se creaba un nuevo enfoque para ayudar al

programador a manejar programas cada vez más 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 pequeños. A continuación se inventó

el lenguaje ensamblador que permitió escribir programas más largos. El siguiente avance ocurrió

en los años 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 líneas. Sin embargo, el método de programación

usado en el comienzo era un enfoque adhoc que no solucionaba mucho. Mientras que esto está

bien para programas relativamente cortos, se convierte en código espagueti ilegible y difícil detratar cuando se aplica a programas más largos. La eliminación del código espagueti se consiguió

con la creación de los lenguajes de programación estructurados en los años 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 podrían llamar programas estructurados.

Los programas estructurados se basan en estructuras de control bien definidas, bloques de código,

la ausencia del GOTO, y subrutinas independientes que soportan recursividad y variables locales.

La esencia de la programación estructurada es la reducción de un programa a sus elementos

constitutivos. Mediante la programación estructurada un programador medio puede crear y

mantener programas de una longitud superior a 50,000 líneas.

Aunque la programación estructurada nos ha llevado a excelentes resultados cuando se ha

aplicado a programas moderadamente complejos, llega a fallar en algún punto cuando el

programa alcanza un cierto tamaño. Para poder escribir programas de mayor complejidad se

necesitaba de un nuevo enfoque en la tarea de programación. A partir de este punto nace la

programación orientada a objetos (POO). La POO toma las mejores ideas incorporadas en la

programación estructurada y las combina con nuevos y potentes conceptos que permiten

Page 6: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 6/62

 

 

organizar los programas de forma más 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 más largos.

Todos los lenguajes de POO comparten tres características: encapsulación, polimorfismo yherencia.

La encapsulación es el mecanismo que agrupa el código y los datos que maneja y los mantiene

protegidos frente a cualquier interferencia y mal uso. En un lenguaje orientado a objetos, el código

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 código como los datos. Cuando el código

y los datos están enlazados de esta manera, se ha creado un objeto. En otras palabras, un objeto

es el dispositivo que soporta encapsulación.

Polimorfismo (del Griego, cuyo significado es muchas formas) es la cualidad que permite que un

nombre se utilice para dos o más propósitos relacionados pero técnicamente diferentes. El

propósito 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 acción específica a

aplicar está determinada por el tipo de dato.

El polimorfismo se puede aplicar tanto a funciones como a operadores, prácticamente todos los

lenguajes de programación contienen una aplicación limitada de polimorfismo cuando se relaciona

con los operadores aritméticos, por ejemplo, en C, el signo + se utiliza para añadir enteros,

enteros largos, caracteres y valores reales. En estos casos, el compilador automáticamente sabe

qué tipo de aritmética 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

añadir aquellas características que son específicamente suyas. La herencia es importante porque

permite que un objeto soporte el concepto de clasificación jerárquica. Mucha información se hace

manejable gracias a esta clasificación, por ejemplo, la descripción de una casa.

Una casa es parte de una clase general llamada edificio, a su vez, edificio es una parte de la clase

más general estructura, que es parte de la clase aún más general de objetos que se puede llamar

obra-hombre.

Page 7: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 7/62

 

 

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, también llamadas métodos. Así, el tipo de datoabstracto es especificado por los métodos, no por los datos. En C++, los tipos de datos abstractos

son representados por clases, las cuales presentan a pequeña 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 vía

#include. Ejemplos de tipos de datos abstractos son: stack, queue, etc

Los TDA por lo general manejan memoria dinámica, esto es, la asignación dinámica de memoria es

una característica que le permite al usuario crear tipos de datos y estructuras de cualquier

tamaño de acuerdo a las necesidades que se tengan en el programa, para ello se emplean

funciones típicas como malloc y free.

Page 8: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 8/62

 

 

1.3 Definición de estructuras de datos. 

En programación, una estructura de datos es una forma de organizar un conjunto de datos

elementales (un dato elemental es la mínima información que se tiene en el sistema) con el

objetivo de facilitar la manipulación de estos datos como un todo y/o individualmente.

Una estructura de datos define la organización e interrelacionamiento de estos, y un conjunto de

operaciones que se pueden realizar sobre él. Las operaciones básicas son:

  Alta, adicionar un nuevo valor a la estructura.

  Baja, borrar un valor de la estructura.

  Búsqueda, encontrar un determinado valor en la estructura para realizar una operación

con este valor, en forma SECUENCIAL o BINARIO (siempre y cuando los datos estén

ordenados).

Otras operaciones que se pueden realizar son:

y  Ordenamiento, de los elementos pertenecientes a la estructura.

y  Apareo, dadas dos estructuras originar una nueva ordenada y que contenga a las

apareadas.

Page 9: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 9/62

 

 8

1.4 Colecciones genéricas de datos. 

Cada estructura ofrece ventajas y desventajas en relación a la simplicidad y eficiencia para la

realización de cada operación. De esta forma, la elección de la estructura de datos apropiada para

cada problema depende de factores como las frecuencias y el orden en que se realiza cadaoperación sobre los datos.

Algunas estructuras de datos utilizadas en programación 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 búsqueda

y  Árbol binario de búsqueda autoajustable

y  Árboles Biselados (Árboles Splay)

o  Árboles Multicamino (Multirrama)

  Árboles B

  Árboles B+

  Árboles B*

  Conjuntos (set)

  Grafos

  Montículos (o heaps)

Page 10: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 10/62

 

 9

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 exploración 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 posición en el soporte de almacenamiento.

Page 11: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 11/62

 

 1

1.6 Iteradores. 

Un iterador es una especie de puntero utilizado por un algoritmo para recorrer los elementosalmacenados en un contenedor. Dado que los distintos algoritmos necesitan recorrer los

contenedores de diversas maneras para realizar diversas operaciones, y los contenedores debenser accedidos de formas distintas, existen diferentes tipos de iteradores. Cada contenedor de laLibrería Estándar puede generar un iterador con funcionalidad adecuada a la técnica dealmacenamiento que utiliza. Es precisamente el tipo de iterador requerido como argumento, loque 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 puedenutilizarse con algoritmos que exijan iteradores de acceso aleatorio.

Un puntero es una variable destinada a contener una dirección de memoria.

Esta dirección generalmente corresponde a otra variable, decimos entonces que el punterocontiene la dirección de la variable o que apunta a ésta.

En el siguiente esquema suponemos que la variable puntero está cargada con el número 4A20.Decimos, entonces, que la dirección 0x4A20 es apuntada por el puntero.

Entre las ventajas que encontramos al usar estos elementos están:

1)  Permiten el acceso a cualquier posición de la memoria, para ser leída o para ser escrita (enlos casos en que esto sea posible).

2)  Permiten la transferencia de argumentos a las funciones, de modo que puedan retener unvalor nuevo, que resulta de aplicarles la función.

3)  Permiten solicitar memoria que no fue reservada al inicio del programa. Esto es el uso dememoria dinámica.

4)  Son el soporte de enlace que utilizan estructuras avanzadas de datos en memoriadinámica como las listas, pilas, colas y árboles.

5)  Operan más eficientemente en los arrays, en comparación con el uso de subíndices.

Page 12: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 12/62

 

 1

1.7 Plantillas (templates). 

La generalidad es una propiedad que permite definir una clase o una función sin tener queespecificar el tipo de todos o alguno de sus miembros. Esta propiedad no es imprescindible en unlenguaje de programación orientado a objetos y ni siquiera es una de sus características. Esta

característica del C++ apareció mucho más tarde que el resto del lenguaje, al final de la década delos 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, undiccionario 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 sedefinen independientemente del tipo de variables que vayan a contener y es el usuario de la claseel que debe indicar ese tipo en el momento de crear un objeto de esa clase.

Plantillas de funciones

Supóngase que se quiere crear una función que devolviese el mínimo entre dos valoresindependientemente de su tipo (se supone que ambos tienen el mismo tipo). Se podría pensar endefinir la función 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 sepuede hacer de la siguiente manera:

// Declaración de la plantilla de función.

template <class T> T minimo( T a, T b);

En ese caso con <classT> se está indicando que se trata de una plantilla cuyo parámetro vaa 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 definición y declaración de la plantilla puede ser que senecesite utilizar más de un tipo de dato e incluido algún otro parámetro constante que pueda

ser utilizado en las declaraciones. Por ejemplo, si hubiera que pasar dos tipos a la plantilla,se podría escribir:

// Declaración de la plantilla de función con dos tipos de datos

template <class T1, class T2> void combinar(T1 a, T2 b);

Podría darse el caso también de que alguno de los argumentos o el valor de retorno fuese deun tipo de dato constante y conocido. En ese caso se indicaría explícitamente como en una

función convencional. La definición de la plantilla de función es como sigue:

// Definición de la plantilla de función

template <class T> T minimo(T a, T b)

{

Page 13: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 13/62

 

 1

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 tambiénalgunas diferencias que pueden hacer necesarias ambas características. El polimorfismo

necesita punteros y su generalidad se limita a jerarquías. Recuérdese que el polimorfismo se basa en que en el momento de compilación se desconoce a qué clase de la

 jerarquía 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 ampliación del polimorfismo. Una desventaja de las plantillas es que tienden a crear un código ejecutablegrande porque se crean tantas versiones de las funciones como son necesarias.

Page 14: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 14/62

 

 1

1.8 La biblioteca STL. 

La Biblioteca Estándar de Patrones, comúnmente conocida en inglés por sus siglas STL (Standard

Template Library) es una biblioteca de C++ que incluye la mayoría de algoritmos y estructuras de

datos que se suelen utilizar en Informática. Básicamente está compuesta de:

  clases contenedoras, es decir, patrones (templates) que permiten almacenar objetos de

muy diversos tipos.

  algoritmos de uso frecuente.

  iteradores, que nos permitirán recorrer los elementos incluidos en los contenedores.

También incluye "objetos función", 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 más fácilmente.

Esta biblioteca es genérica en tanto sus componentes están 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 programación 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 inserción).

  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.

Page 15: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 15/62

 

 1

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.

Page 16: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 16/62

 

 1

Pregunt as de autoevaluación. 

Page 17: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 17/62

 

 1

TEMA 2 

ARREGLOS.

Identificar y usar el tipo de estructura conocida como arreglo para dar solución a necesidades de

organización de datos que se presenten.

2.1 Arreglos lineales dinámicos. 

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 subíndices.

Sintaxis:

<tipo><identificador>[<núm_elemen>][[<núm_elemen>]...];

Los valores para el número de elementos deben ser constantes, y se pueden usar tantas

dimensiones como queramos, limitado sólo por la memoria disponible.

Cuando sólo se usa una dimensión 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 dimensión de objetos de tipo char.

Los subíndices son enteros, y pueden tomar valores desde 0 hasta <número de elementos>-1.

En general C++ no verifica el ámbito de los subíndices. 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 código 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 número de elementos del que va a constar el array, o no se

quiere poner un límite predetermiado, lo que hay que hacer es definir el array dinámicamente.

Para hacer esto, primero se define un puntero, que señalará la dirección de memoria del primer

elemento del array: tipo_de_elemento *nombre_de_array; 

Page 18: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 18/62

 

 1

y luego se utiliza la función malloc (contenida en stdlib.h) para reservar memoria:

nombre_de_array=(tipo_de_elemento *)malloc(tamaño);

donde tamaño es el número de elementos del array por el tamaño en bytes de cada elemento. La

función malloc devuelve un puntero void, que indica la posición del primer elemento. Antes de

asignarlo a nuestro puntero, hay que convertir el puntero que devuelve el malloc al tipo denuestro puntero (ya que no se pueden igualar punteros de distintos tipos).

Page 19: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 19/62

 

 1

2.2 Represent ación 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 subíndice podremos usar cualquier expresión entera.

Los arrays pueden ser inicializados en la declaración.

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 tamaño para la primera dimensión, como ocurre en

los ejemplos de las líneas 2, 3, 4, 5 y 6. En estos casos la dimensión que queda indefinida se calcula

a partir del número de elementos en la lista de valores iniciales.

En el caso 2, el número 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 dimensión es 3: 9/3=3.

Y en el caso 5, el número de elementos es 17, 16 caracteres más el cero de fin de cadena.

Page 20: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 20/62

 

 1

2.3 Operaciones con arreglos. 

Ya hemos visto que se puede usar el operador de asignación 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 tamaño de todo el array en bytes. Podemosobtener el número de elementos dividiendo ese valor entre el tamaño de uno de los elementos.

#include <iostream>using namespace std;

int main(){

int array[231];cout << "Número de elementos: "

<< sizeof(array)/sizeof(int) << endl;

cout << "Número de elementos: "<< sizeof(array)/sizeof(array[0]) << endl;cin.get();

return 0;}

Las dos formas son válidas, pero la segunda es, tal vez, más general.

Page 21: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 21/62

 

 2

2.4 Arreglos dinámicos. 

Si al iniciar un programa no se sabe el número de elementos del que va a constar el array, o no se

quiere poner un límite predetermiado, lo que hay que hacer es definir el array dinámicamente.

Para hacer esto, primero se define un puntero, que señalará la dirección de memoria del primerelemento del array:

tipo_de_elemento *nombre_de_array;

y luego se utiliza la función malloc (contenida en stdlib.h) para reservar memoria:

nombre_de_array=(tipo_de_elemento *)malloc(tamaño);

Donde tamaño es el número de elementos del array por el tamaño en bytes de cada elemento. La

función malloc devuelve un puntero void, que indica la posición del primer elemento. Antes de

asignarlo a nuestro puntero, hay que convertir el puntero que devuelve el malloc al tipo denuestro puntero (ya que no se pueden igualar punteros de distintos tipos).

Para arrays bidimensionales, hay que hacerlo dimensión a dimensión; 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 más de dos dimensiones, se hace de

forma similar.

Page 22: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 22/62

 

 2

2.5 Punteros y arreglos de punteros. 

Un puntero es una variable destinada a contener una dirección de memoria.

Esta dirección generalmente corresponde a otra variable, decimos entonces que el puntero

contiene la dirección 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 indirección 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 declaración, 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 rótulo 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 día;

int mes;

int anio;

Page 23: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 23/62

 

 2

};

struct fecha hoy;

struct fecha * F;

F todavía no apunta a una dirección válida. Hacemos que F apunte a hoy, cargándolo con la

dirección 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 dirección. Por eso usamos el operador mencionado.

Page 24: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 24/62

 

 2

2.6 La clase VECTOR. 

Aunque cada uno de los contenedores que ofrece la STL tienen características diferentes, en esta

sección presentaremos el contenedor vector. El contenedor vector permite almacenar cero o más

objetos del mismo tipo, pudiendo acceder a ellos individualmente mediante un índice, es decir,acceso aleatorio. En este sentido, es una extensión del vector o array que ofrece C++, aunque en

este caso el número de elementos de un objeto vector puede variar dinámicamente. La gestión de

la memoria se hace de manera totalmente transparente al usuario. Se define como una clase

patrón, lo que implica que puede albergar objetos de cualquier tipo. En cuanto a las operaciones

más frecuentes, ofrece un tiempo constante en inserción y borrados de elementos al final, y lineal

al comienzo o en la mitad del vector.

La declaración más común 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í, podríamos declarar los siguientes vectores:

vector<double> vectorReales; // De números reales.

vector<string> vectorCadenas; // De cadenas de caracteres.

vector<MiClase> vectorObj; // Contendrá objetos de una clase construida por un usuario

Una declaración:

vector <int> vectorEnteros(10);

Crea un vector de diez enteros. Si deseamos inicializarlo a algún valor en concreto, entoncesañadimos un argumento más al constructor:

vector <int> vectorEnteros(10,-1)

De manera general las funciones miembro y operadores manejados por vector más utilizadas son:

Page 25: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 25/62

 

 2

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 más 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;

}

Page 26: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 26/62

 

 2

Pregunt as de autoevaluación. 

Page 27: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 27/62

 

 2

TEMA 3 

LISTAS.

Identificar y usar el tipo de estructura conocida como lista para dar solución a necesidades de

organización de datos que se presenten.

3.1 Definición de list a. 

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, según se requiera. Es más,podemos insertar o eliminar elementos en cualquier posición de una lista.

Las listas se pueden implementar de 2 modos distintos: mediante vectores o mediante estructuras

dinámicas enlazadas por apuntadores. El trabajo de listas con vectores tiene una limitante: las

listas tienen una longitud variable (dinámicas) y los vectores tienen longitud estática. No

podríamos definir un arreglo de tamaño N donde solamente utilicemos los primero N-m cajones.

O viceversa, declarar un arreglo demasiado pequeño para nuestras necesidades. Esto es el porqué

de las estructuras dinámicas de datos.

La forma más simple de estructura dinámica es la lista. En esta forma los nodos se organizan demodo 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 l ista.

Cuando el puntero que usamos para acceder a la lista vale NULL, diremos que la lista está vacía. El

nodo típico para construir listas tiene esta forma:

En el ejemplo, cada elemento de la lista sólo contiene un dato de tipo entero, pero en la práctica

no hay límite en cuanto a la complejidad de los datos a almacenar.

Page 28: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 28/62

 

 2

3.2 Asignación de memoria a la list a. 

Normalmente se definen varios tipos que facilitan el manejo de las listas, la declaración de tipos

puede tener una forma en memoria parecida a esta:

Dónde:

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.

Page 29: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 29/62

 

 2

3.3 La clase list a de STL. 

El contenedor de decencia LIST cuenta con una eficiente combinación para las operaciones de

inserción y eliminación en cualquier posición 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 atrás.

Además 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.

Page 30: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 30/62

 

 2

3.4 Iteradores para la clase list a. 

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 pequeño repertorio de operaciones básicas que se pueden

realizar:

y  Añadir o insertar elementos.

y  Buscar o localizar elementos.

y  Borrar elementos.

y  Moverse a través 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 vacía, o al principio de una lista no vacía, o la final, o en una posición

intermedia.

A continuación se describen algunos programas de ejmplo con iteradores.

List::const_iterator (STL/CLR)

En esta aplicación 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 debería ser el siguiente: a b c

Page 31: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 31/62

 

 3

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 elementcliext::list<wchar_t>::const_reference cref = *cit;System::Console::Write(" {0}", cref);}

System::Console::WriteLine();return (0);

}

El resultado debera ser: a b c

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');

Page 32: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 32/62

 

 3

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 redisplayit = 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 

Page 33: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 33/62

 

 3

3.5 Construcción de list as. 

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

vacía:

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 vacía:

El proceso en este caso tampoco es excesivamente complicado:

1. Necesitamos un puntero que señale 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.

Page 34: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 34/62

 

 3

3.6 Algoritmos genéricos sobre colecciones de STL. 

La librería estándar proveeherramientasquefacilitanla programacion.Eselcasodelos

string,quepermitenevitarlosproblemasmas clásicos conlascadenasdecaracteresalaC.

strings1(Primera);

strings2=Segunda;

strings3=s1+ y +s2;

s3.append(y aun mas);

La librera estándar también provee,fueradetodaclase/patron, código

generico,implementadocomo funcionespatrones.Sonabstraccionesdefuncionesrecurrentesen

código C++.

Esta funcion copiatodosloselementosdentrodeunarreglo,dentrodeunoslimites(dadosen términos

deapuntadores),haciaotroarreglo.Seahorraescribirciclos!

Como estaimplementadocomo template,sepuedeusar cualquiertipodeapuntador.

Page 35: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 35/62

 

 3

Pregunt as de autoevaluación. 

Page 36: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 36/62

 

 3

TEMA 4 

PILAS.

Identificar y usar el tipo de estructura conocida como pila para dar solución a necesidades de

organización de datos que se presenten.

4.1 Definición de pilas. 

Una pila es un tipo especial de lista abierta en la que sólo 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". Además, las escrituras de datos siempre son inserciones de

nodos, y las lecturas siempre eliminan el nodo leído.

Estas características implican un comportamiento de lista LIFO (Last In First Out), el último en

entrar es el primero en salir. La más sencilla de las estructuras dinámicas 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 dinámica: 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.

Page 37: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 37/62

 

 3

4.2 Implement ación de pilas. 

El nodo típico para construir pilas es el siguiente:

Los tipos que se definen normalmente para manejar pilas son casi los mismos que para manejar

listas, tan sólo se cambian algunos nombres de la siguiente manera:

Dónde:

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 gráfica de ver la estructura sería:

Es evidente, a la vista del gráfico, 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.

Page 38: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 38/62

 

 3

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

vacía o no y size para obtener el número 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 estándar.

#include <iostream>

using std::cout;

using std::endl;

#include <stack> // definición del adaptador stack

#include <vector> // definición de la plantilla de clase vector

#include <list> // definición de la plantilla de clase list

// prototipo de la plantilla de función sacarElementostemplate< 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 ) {

Page 39: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 39/62

 

 3

intDequePila.push( i );

intVectorPila.push( i );

intListaPila.push( i );

} // fin de instrucción 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 instrucción while

} // fin de la función sacarElementos

Page 40: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 40/62

 

 3

4.4 Iteradores para la clase St ack. 

El termino iterar significa (en palabras sencillas) el método o forma que se usa para poder navegar

sobre los elementos de una lista específica. 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 atención

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 declaración 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 método 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 sólo se expondrá la parte

inicial donde se hace referencia a la definición 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.top()<<endl;

s.pop();

} cout<<" ";

system("pause");

}

 

Page 41: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 41/62

 

 4

4.5Construcción de Pilas. 

Supongamos que queremos construir una pila para almacenar números 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 función "pop":

1. Hacemos que nodo apunte al primer elemento de la pila, es decir, a Pila.

2. Asignamos a Pila la dirección 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.

Page 42: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 42/62

 

 4

También 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. Además la clase para nodo

debe ser amiga de la clase pila, ya que ésta debe acceder a los miembros privados de nodo.

Page 43: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 43/62

 

 4

Pregunt as de autoevaluación. 

Page 44: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 44/62

 

 4

TEMA 5 

COLAS.

Identificar y usar el tipo de estructura conocida como cola para dar solución a necesidades de

organización de datos que se presenten.

5.1 Definición de colas. 

Una cola es un tipo especial de lista abierta en la que sólo se puede insertar nodos en uno de los

extremos de la lista y sólo se pueden eliminar nodos en el otro. Además, como sucede con las

pilas, las escrituras de datos siempre son inserciones de nodos, y las lecturas siempre eliminan el

nodo leído.

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 sólo pueden colocarse al final de la cola, y sólo el primero de la cola puede comprar

la entrada.

Page 45: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 45/62

 

 4

5.2 Construcción de colas. 

El nodo típico para construir colas es el mismo para la construcción de listas y pilas:

Los tipos que se definen normalmente para manejar colas son casi los mismos que para manejar

listas y pilas, tan sólo se cambian algunos nombres:

Dónde:

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 gráficamente 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. Además, debido al funcionamiento de las colas, también 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 más fácil será insertar nodos por el final, a continuación del nodo que no tiene nodo

siguiente, y leerlos desde el principio, hay que recordar que leer un nodo implica eliminarlo de la

cola.

Page 46: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 46/62

 

 4

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 vacía y size para obtener el número 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 estándar.

#include <iostream>

using std::cout;

using std::endl;

#include <queue> // definición 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 instrucción while

cout << endl;

return 0;

} // fin de main

Page 47: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 47/62

 

 4

5.4 Iteradores para la clase Queue. 

Supóngase que construimos una cola para almacenar números 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 vacía, añadimos el nuevo a continuación 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 vacía, ahora primero apuntará también al

nuevo nodo */

if(!*primero) *primero = nuevo;}

Algoritmo de la función "leer":

1. Hacemos que nodo apunte al primer elemento de la cola, es decir a primero.

2. Asignamos a primero la dirección 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 también apunte a NULL, ya que la cola habrá quedado

vacía.

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;

Page 48: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 48/62

 

 4

if(!nodo) return 0; /* Si no hay nodos en la pila retornamos 0 *//* Asignamos a primero la dirección del segundo nodo */*primero = nodo->siguiente;/* Guardamos el valor de retorno */v = nodo->valor;/* Borrar el nodo */free(nodo);/* Si la cola quedó vacía, ultimo debe ser NULL también*/if(!*primero) *ultimo = NULL;return v;

}

Page 49: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 49/62

 

 4

Pregunt as de autoevaluación. 

Page 50: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 50/62

 

 4

TEMA 6 

ARBOLES.

Identificar y usar el tipo de estructura conocida como árbol para dar solución a necesidades de

organización de datos que se presenten.

6.1 Definición de árbol. 

Un árbol es una estructura no lineal en la que cada nodo puede apuntar a uno o varios nodos.

También se suele dar una definición recursiva: un árbol es una estructura en compuesta por un

dato y varios árboles, la forma gráfica se puede apreciar como sigue:

En relación 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 posición dentro del árbol, encontramos:

y  Nodo raíz: nodo que no tiene padre. Este es el nodo que usaremos para referirnos al

árbol. En el ejemplo, ese nodo es el 'A'.

y  Nodo hoja: nodo que no tiene hijos. En el ejemplo hay varios: 'F', 'H', 'I', 'K', 'L', 'M', 'N' y

'O'.

Page 51: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 51/62

 

 5

y  Nodo rama: aunque esta definición apenas la usaremos, estos son los nodos que no

pertenecen a ninguna de las dos categorías 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 raíz de un árbol completo.

Page 52: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 52/62

 

 5

6.2 Árboles binarios. 

Los árboles de orden dos son bastante especiales, de hecho les dedicaremos varios capítulos.

Estos árboles se conocen también como árboles binarios.

Frecuentemente, aunque no es estrictamente necesario, para hacer más fácil el moverse a través

del árbol, se añade un puntero a cada nodo que apunte al nodo padre. De este modo podremos

avanzar en dirección a la raíz, y no sólo hacia las hojas.

Un árbol binario esta vacío o consta de un nodo denominado raíz junto con dos árboles binarios

llamados subárbol izquierdo y subárbol derecho de la raíz.

Además de que los árboles binarios se emplean para búsquedas, la recuperación de información

es una de las aplicaciones más importantes, y para ello existen los árboles de búsqueda binaria.

Page 53: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 53/62

 

 5

6.3 Represent ación de árboles binarios en memoria. 

La única manera de construir un árbol binario con un nodo consiste en hacer que el nodo sea su

raíz y que estén vacíos sus subárboles 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 raíz y el otro estará en un subárbol. Así, uno de los

subárboles de la izquierda o derecha debe estar vacío 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 raíz y los otros dos se dividirán

entre los subárboles 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 vacío, en el primer caso da dos

árboles binarios. El tercero también lo hace. En el segundo caso, los subárboles 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 representación natural en el almacenamiento de listas ligadas.

Page 54: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 54/62

 

 5

6.4Recorrido de árboles. 

El modo evidente de moverse a través de las ramas de un árbol es siguiendo los punteros, del

mismo modo en que nos movíamos a través de las listas.

Esos recorridos dependen en gran medida del tipo y propósito 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 raíz:

RecorrerArbol(raiz);

La función RecorrerArbol, aplicando recursividad, será tan sencilla como invocar de nuevo a la

función 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 métodos de recorrer el árbol no es el sistema de hacerlo, sino el

momento que elegimos para procesar el valor de cada nodo con relación a los recorridos de cada

una de las ramas.

Los tres tipos son:

Page 55: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 55/62

 

 5

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í:

A B E K F C G L M D H I J N O

In-orden:

En este tipo de recorrido, el valor del nodo se procesa después de recorrer la primera rama y antes

de recorrer la última. Esto tiene más sentido en el caso de árboles binarios, y también 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í:

K E B F A L G M C H D I N J O

Post-orden:

En este tipo de recorrido, el valor del nodo se procesa después 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

Page 56: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 56/62

 

 5

6.5 Arboles binarios de búsqueda. 

Se trata de árboles de orden 2 en los que se cumple que para cada nodo, el valor del nodo raíz del

subárbol izquierdo es menor que el valor del nodo raíz y que el valor del nodo raíz del subárbol

derecho es mayor que el valor del nodo raíz.

Page 57: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 57/62

 

 5

6.6Búsqueda e inserción de árboles binarios de búsqueda. 

Buscar un elemento.

Partiendo siempre del nodo raíz, el modo de buscar un elemento se define de forma recursiva

como:

  Si el árbol está vacío, terminamos la búsqueda: el elemento no está en el árbol.

  Si el valor del nodo raíz es igual que el del elemento que buscamos, terminamos la

búsqueda con éxito.

  Si el valor del nodo raíz es mayor que el elemento que buscamos, continuaremos la

búsqueda en el árbol izquierdo.

  Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos la

búsqueda en el árbol derecho. 

El valor de retorno de una función de búsqueda en un ABB puede ser un puntero al nodoencontrado, o NULL, si no se ha encontrado.

Insertar un elemento.

Para insertar un elemento nos basamos en el algoritmo de búsqueda. Si el elemento está en el

árbol no lo insertaremos. Si no lo está, lo insertaremos a continuación del último nodo visitado.

Para ello, se necesita un puntero auxiliar para conservar una referencia al padre del nodo raíz

actual. El valor inicial para ese puntero es NULL.

y  Padre = NULL

y  nodo = Raiz

y  Bucle: mientras actual no sea un árbol vacío o hasta que se encuentre el elemento. o  Si el valor del nodo raíz es mayor que el elemento que buscamos, continuaremos

la búsqueda en el árbol izquierdo: Padre=nodo, nodo=nodo->izquierdo

o  Si el valor del nodo raíz es menor que el elemento que buscamos, continuaremos

la búsqueda en el árbol derecho: Padre=nodo, nodo=nodo->derecho.

y  Si nodo no es NULL, el elemento está en el árbol, por lo tanto salimos.

y Si Padre es NULL, el árbol estaba vacío, por lo tanto, el nuevo árbol sólo contendrá elnuevo elemento, que será la raíz del árbol.

y  Si el elemento es menor que el Padre, entonces insertamos el nuevo elemento como un

nuevo árbol izquierdo de Padre.

y  Si el elemento es mayor que el Padre, entonces insertamos el nuevo elemento como un

nuevo árbol derecho de Padre.

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

Page 58: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 58/62

 

 5

6.7 Árboles degenerados. 

Los árboles binarios de búsqueda 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

Difícilmente podremos llamar a la estructura resultante un árbol:

Esto es lo que llamamos un árbol binario de búsqueda degenerado, y el árbol AVL, es la estructura

que resuelve este problema, generando árboles de búsqueda equilibrados.

Page 59: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 59/62

 

 5

6.8 Aplicaciones 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,

podríamos considerar que los nodos hoja son archivos y los nodos rama son directorios.

Otro ejemplo podría ser la tabla de contenido de un libro, por ejemplo de este mismo manual,

dividido en capítulos, y cada uno de ellos en subcapítulos. Aunque el libro sea algo lineal, como

una lista, en el que cada capítulo sigue al anterior, también es posible acceder a cualquier punto

de él a través de la tabla de contenido.

También se suelen organizar en forma de árbol los organigramas de mando en empresas o en el

ejército, y los árboles genealógicos.

Page 60: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 60/62

 

 5

Pregunt as de autoevaluación. 

Page 61: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 61/62

 

 6

CONCLUSIONES

Las estructuras de datos y algoritmos que faciliten su comprensión y desarrollo, constituyen

elementos básicos en el almacenamiento y tratamiento de la información.

El entendimiento y conocimiento del concepto de estructuras y sus representaciones y métodos

que desembocan en el desarrollo de programas constituyen un previo indispensable para

introducirse en el ámbito de la programación.

Page 62: Estructura de datos

5/8/2018 Estructura de datos - slidepdf.com

http://slidepdf.com/reader/full/estructura-de-datos-559abe4db4fe4 62/62

 

 6

BIBLIOGRAFÍA

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, abstracción y objetos.Luis Joyanes Aguilar, Ignacio Zahonero Martínez.

McGraw Hill.

Guia de Autoenseñanza C++

Herbert Schildt

McGraw Hill.

Manual de Estructuras dinámicas de datos.

Salvador Pozo.