Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
ESTRUCTURAS DE DATOS
Un enfoque orientado a objetos
SASCI
2009
APUNTES DE
ESTRUCTURAS DE DATOS
Un enfoque orientado a objetos
Estos apuntes están dedicados a todos aquellos que están dispuestos a sacrificar horas de
descanso o diversión, con el fin de superarse permanentemente, hacerse mejores y hacer un
mundo mejor.
El autor
Tabla de contenido
PREFACIO ............................................................................................................................................................ 3
1. ESTRUCTURAS Y ABSTRACCIÓN DE DATOS ...................................................................................................... 1
1.1. INTRODUCCIÓN A LAS ESTRUCTURAS DE DATOS ........................................................................................... 1
1.2. ABSTRACCIÓN DE DATOS .............................................................................................................................. 1
1.3. CLASIFICACIÓN DE LAS ESTRUCTURAS DE DATOS ......................................................................................................... 2
1.4. TIPOS ABSTRACTOS DE DATOS............................................................................................................................... 2
Operaciones con arreglos ................................................................................................................................. 4
1.6 BÚSQUEDA Y CLASIFICACIÓN DE ARREGLOS ................................................................................................................ 4
Búsqueda secuencial ........................................................................................................................................ 5
Búsqueda binaria ............................................................................................................................................. 5
Clasificación ..................................................................................................................................................... 6
Método de intercambio o de Burbuja ............................................................................................................... 7
Método de la Baraja ........................................................................................................................................ 8
Metodo QuickSort ............................................................................................................................................ 8
2. ESTRUCTURA DE LENGUAJES DE PROGRAMACIÓN ORIENTADOS A OBJETO..................................................... 10
2.1 . ASPECTOS GENERALES DE LOS LENGUAJES .......................................................................................... 10
2.2 LENGUAJES ORIENTADOS A OBJETO ........................................................................................................................ 12
2.2. ESTRUCTURAS DE DATOS ORIENTADAS A OBJETOS ..................................................................................................... 14
2.4. RECURSIVIDAD Y LENGUAJES DE PROGRAMACIÓN OO................................................................................................ 15
Concepto de Recursividad............................................................................................................................... 15
1. Cálculo de la potencia................................................................................................................................. 17
2. La suma de forma recursiva ........................................................................................................................ 18
3. Búsqueda lineal recursiva (con dos casos base) ........................................................................................... 18
4. Búsqueda Binaria recursiva ........................................................................................................................ 18
3. ALMACENAMIENTO ESTÁTICO EN SECUENCIA – LISTAS .................................................................................... 20
3.1 ASPECTOS GENERALES DE LISTAS ........................................................................................................................... 20
3.2. PILAS ............................................................................................................................................................ 20
Aplicación de pila: Evaluación de expresiones ................................................................................................. 21
Transformación de infija a postfija ................................................................................................................. 22
3.3. COLAS ........................................................................................................................................................... 24
Operaciones Básicas....................................................................................................................................... 25
Aplicaciones ................................................................................................................................................... 25
IMPLEMENTACIÓN DE COLAS EN C++ ........................................................................................................................... 26
Tipos de colas ................................................................................................................................................ 27
Aplicación de cola: Colas de atención al público en un banco .......................................................................... 28
4.1 MANEJO DINÁMICO DE LA MEMORIA – LOS PUNTEROS ............................................................................................... 29
¿Que es una variable? .................................................................................................................................... 29
Punteros ........................................................................................................................................................ 31
4.2. LISTAS ENCADENADAS ....................................................................................................................................... 33
4.3 DISEÑO E IMPLEMENTACIÓN DINÁMICA DE LISTAS ENCADENADAS .................................................................................. 34
Estructura de Nodo ........................................................................................................................................ 34
Estructura de Lista encadenada...................................................................................................................... 35
Esquema y diseño de una lista enlazada ......................................................................................................... 35
Operación de Recorrido .................................................................................................................................. 37
Operación de Inserción ................................................................................................................................... 38
Operación de Borrado .................................................................................................................................... 39
Operación de Búsqueda ................................................................................................................................. 39
4.4. IMPLEMENTACIÓN DINÁMICA DE ESTRUCTURAS DE DATOS .......................................................................................... 39
Implementación de pilas con punteros............................................................................................................ 39
5. ARBOLES Y GRAFOS........................................................................................................................................... 40
5.1 ARBOLES BINARIOS ............................................................................................................................................ 40
Definición de árbol ......................................................................................................................................... 41
Formas de representación .............................................................................................................................. 41
Declaración de árbol binario........................................................................................................................... 42
Recorridos sobre árboles binarios ................................................................................................................... 42
Construcción de un árbol binario .................................................................................................................... 44
5.2 ÁRBOL BINARIO DE BÚSQUEDA ............................................................................................................................. 46
Operaciones básicas sobre árboles binarios de búsqueda................................................................................ 47
Ejercicio resuelto ............................................................................................................................................ 50
Aplicación práctica de un árbol binario de búsqueda ...................................................................................... 50
Ejercicios propuestos...................................................................................................................................... 51
5.3. ÁRBOLES B ..................................................................................................................................................... 53
Utilización de los Arboles B............................................................................................................................. 53
Funcionamiento ............................................................................................................................................. 54
¿Qué es un Arbol B? ....................................................................................................................................... 56
Costos............................................................................................................................................................ 60
Casos especiales............................................................................................................................................. 61
Conclusión ..................................................................................................................................................... 62
TRABAJOS PRACTICOS............................................................................................................................... 63
BIBLIOGRAFÍA .................................................................................................................................................... 66
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Los programas están constituidos fundamentalmente por algoritmos y estructuras de datos. Esto
significa que los algoritmos se ejecutan sobre estas estructuras de datos. Esto permite ver que las
estructuras de datos son una parte fundamental de la programación de computadoras, en
particular; y del procesamiento de información, en general
Una estructura de datos es una colección de datos que pueden ser caracterizados por su
organización y las operaciones que se definen sobre ella.
Así los lenguajes de programación proporcionan una serie de tipos de datos simples, como son
los números enteros, caracteres, números reales. En realidad los lenguajes suministran un modelo
de datos que son un subconjunto finito de éstos, pues la memoria del ordenador es finita. Los
punteros o apuntadores (si los tiene) son también un tipo de datos. El tamaño de cada tipo de
datos depende de la máquina y del compilador sobre los que se trabaja.
1
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Las estructuras estáticas son aquellas en las que el tamaño ocupado en memoria se define antes
de que el programa se ejecute y no puede modificarse dicho tamaño durante la ejecución del
programa. Cuando el número de datos es grande, las operaciones de inserción y eliminación de
elementos es una tarea relativamente pesada; es decir los algoritmo deben realizar movimiento de
grandes cantidades de datos de una posición a otra. En general ocupan un tamaño fijo de
memoria, aunque hay algunos lenguajes que permiten redefinir su tamaño en pena ejecución. Las
estructuras estáticas se clasifican en arreglos, registros, archivos, conjuntos y strings.
Por otro lado, las estructuras dinámicas no tienen limitaciones en el tamaño de memoria ocupada
que son propias de las estructuras estáticas. El tamaño de las estructuras dinámicas se amplía y
contrae durante la ejecución del programa. Las estructuras dinámicas se clasifican en lineales y
no lineales. Las lineales son las pilas, colas y listas enlazadas. Las no lineales son los árboles y
los grafos.
Los Tipos Abstractos de Datos (TAD) permiten describir una estructura de datos en función de
las operaciones que pueden efectuar, dejando de lado su implementación. Esto se denomina
abstracción de datos o tipo abstracto de datos. En realidad los propios tipos de datos provistos por
los lenguajes de programación son Tipos Abstractos de Datos. Otros ejemplos son tipos muy
específicos de datos como ser TAD fecha, TAD hora, TAD Polinomio, TAD Racional, TAD
Array, etc.
Los TAD combinan estructuras de datos junto a una serie de operaciones de manipulación.
Incluyen una especificación sobre lo que verá el usuario, y una implementación (algoritmos de
operaciones sobre las estructuras de datos y su representación en un lenguaje de programación),
que el usuario no tiene necesariamente que conocer para manipular correctamente los tipos
abstractos de datos.
Se caracterizan por el encapsulamiento. Es como una caja negra que funciona simplemente
conectándole unos cables. Esto permite aumentar la complejidad de los programas pero
manteniendo una claridad suficiente que no desborde a los desarrolladores. Además, en caso de
que algo falle será más fácil determinar si lo que falla es la caja negra o son los cables.
2
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Por último, indicar que un TAD puede ser construido a partir de otro TAD ya definido. Por
ejemplo se pueden definir pilas, colas y árboles a partir de arrays o listas enlazadas. De hecho, las
listas enlazadas también pueden construirse a partir de arrays y viceversa.
Los tipos de datos abstractos (TAD) describen un conjunto de objetos con la misma
representación y comportamiento. Los tipos abstractos de datos representan una separación clara
entre la interfaz externa de un tipo de dato (nivel lógico) y su implementación interna (nivel
físico). La implementación de un tipo abstracto de datos está oculta, por consiguiente se pueden
utilizar implementaciones alternativas para un mismo tipo abstracto de datos sin cambiar su
interfaz favoreciendo así las etapas de corrección y depuración del software pues se puede
cambiar o mejorar un algoritmo interno sin cambiar su interfaz de modo tal que no afecta a los
demás módulos del software.
Hoy en día con los nuevos paradigmas de programación orientada a objetos, la aplicación de los
conceptos de abstracción se aplican mejor en paquetes cerrados llamados (clases) los cuales
presentan una interfaz al usuario de estas clases permitiendo solo el acceso a los métodos y
operaciones definidas para este T.A.D., ocultando los detalles de la implementación de tales
métodos, aplicando así el concepto de abstracción y facilitando al diseñador del software pues
este utilizara dicha interfaz para construir aplicaciones sin la necesidad de preocuparse por
detalles de la implementación del (T.A.D) Gracias a este concepto de abstracción y la aplicación
de la programación orientada a objetos hoy por hoy se agiliza grandemente la realización de
proyectos de desarrollo de software desde proyectos que se terminaban en aproximadamente un
año, a un mes; causando un gran impacto en el mercado del software. Por tanto las compañías de
desarrollo de software que no apliquen estos conceptos tienden a quedar en una gran desventaja
con sus competidores.
En términos formales, a nivel lógico una Estructura de Datos d se define como una tripleta
compuesta por con conjunto de dominios D, un conjunto de funciones u operaciones F y un
conjunto de axiomas A.
d = (D, F, A)
donde:
D El conjunto de dominios consiste en los tipos de datos primitivos que utiliza la estructura
F Es el conjunto de funciones que manipulan los datos
A Describen el significado de las funciones
Un arreglo es una estructura de datos que consiste en un conjunto de pares índice-valor, sobre la
que se definen las operaciones de almacenamiento y recuperación. Todos los valores o elementos
3
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
de una rreglo son del mismo tipo, es decir es una estructura homogénea. El almacenamiento se
hace asociando un valor con cada índice y la recuperación significa que a partir de un índice se
puede obtener el valor.
Aquí en conjunto dominios serían los enteros (para los índices) y un tipo de dato (para los
valores), el conjunto de operaciones serían añadir un valor y recuperar un valor. Los axiomas
sería el significado de añadir un valor y el significado de recuperar un valor.
Valores
(elementos)
Indices
(posiciones)
Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre Noviembre Diciembre
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]
Para realizar operaciones con arreglos, es necesario hacer operaciones a nivel de cada elemento;
es decir, por ejemplo cargar con datos un arreglo (leer) significara cargar cada elemento mediante
una instrucción apropiada del lenguaje de programación.
Las principales operaciones con arreglos son: leer, imprimir, buscar máximo y mínimo, hallar
totales y subtotales, buscar un elemento, clasificar u ordenar un arreglo.
4
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Búsqueda secuencial
También llamada búsqueda lineal. Este proceso consiste en que dado el valor que se busca, se lo
debe comparar con cada valor del arreglo hasta dar con el que se busca; en ese momento se
captura la posición o índice. En caso de haber revisado todos los valores y no encontrar el valor,
se dirá que el valor no se encuentra. Un algoritmo para este proceso es el siguiente:
El algoritmo de búsqueda secuencial no es optimo para cuando el tamaño del vector es grande,
puesto que el número de comprobaciones (si-entonces) es, en promedio, (n+1)/2, es decir
aproximadamente igual a la mitad de los elementos del vector.
Búsqueda binaria
Si los datos que se buscan están clasificados en un determinado órden, el método de las mitades
será más adecuado. Este método se denomina búsqueda binaria.
La búsqueda binaria utiliza un método llamado “divide y vencerás” para localizar el valor
deseado. Con este método se examina primero el elemento central de la lista; si este es el
elemento buscado, entonces la búsqueda ha terminado. En caso contrario, se determina si el
elemento buscado está en la primera o segunda mitad de la lista y, a continuación se repite el
proceso, utilizando el elemento central de esta sublista.
5
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
No olvidemos que la búsqueda binaria requiere que el vector esté ordenado, y en la práctica esta
condición puede ser difícil de mantener, sin embargo, en contrapartida, la búsqueda binaria es un
método muy rápido ya que el número de comparaciones es pequeño en relación al tamaño del
vector. Se ha determinado que el número máximo de comparaciones esta dado por log2 n.
Esto significará que si se tienen100 elementos, requerirán solo 7 comparaciones como máximo.
Si son 100000 elementos, el número de comparaciones será de 20.
Clasificación
6
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Ordenación de arreglos
Ordenación de archivos (ordenación externa)
En este curso veremos solo la ordenación interna. Los principales métodos de ordenación de
arreglos son:
Inserción
o Inserción directa (baraja)
o Inserción binaria
Intercambio
o Burbuja
o Pares no adyacentes
Selección
Shell
Ordenación rápida (quick-sort)
7
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Inicio
temporal = x
x=y
y = temporal
Fin
Método de la Baraja
Es un método de inserción, consiste en insertar un elemento en una parte del vector ya ordenada y
comenzar de nuevo con los elementos restantes. Por ser utilizado generalmente por los jugadores
de cartas se le conoce con el nombre de Baraja.
Metodo QuickSort
8
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La lista queda separada en dos sublistas, una formada por los elementos a la izquierda del
pivote, y otra por los elementos a su derecha.
Repetir este proceso de forma recursiva para cada sublista mientras éstas contengan más de
un elemento. Una vez terminado este proceso todos los elementos estarán ordenados.
Como se puede suponer, la eficiencia del algoritmo depende de la posición en la que termine el
pivote elegido.
En el mejor caso, el pivote termina en el centro de la lista, dividiéndola en dos sublistas de
igual tamaño. En este caso, el orden de complejidad del algoritmo es O(n·log n).
En el peor caso, el pivote termina en un extremo de la lista. El orden de complejidad del
algoritmo es entonces de O(n²). El peor caso dependerá de la implementación del algoritmo,
aunque habitualmente ocurre en listas que se encuentran ordenadas, o casi ordenadas.
En el caso promedio, el orden es O(n·log n).
9
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
En los primeros estadios de desarrollo de los lenguajes de programación (Basic, Fortran) se tenía
un código en el que no había separación de conceptos, datos y funcionalidad se mezclaban sin
una línea divisoria clara. A esta etapa se la conoce como la del código spaghetti, ya que se tenía
una maraña entre datos y funcionalidad que recuerda a la que se forma del plato de esta pasta
italiana. En la siguiente etapa (Algol, Pascal, C) se pasó a aplicar la llamada descomposición
funcional, (da origen a la llamada programación modular) que pone en práctica el principio de
„divide y vencerás‟ identificando las partes más manejables como funciones que se definen en el
dominio del problema. La principal ventaja que proporciona esta descomposición es la facilidad
de integración de nuevas funciones, aunque también tiene grandes inconvenientes, como son el
hecho de que las funciones quedan algunas veces poco claras debido a la utilización de datos
compartidos, y el que los datos quedan esparcidos por todo el código, con lo cual, normalmente el
integrar un nuevo tipo de datos implica que se tengan que modificar varias funciones.
Intentando solventar estas desventajas con respecto a los datos, se dio otro paso en el desarrollo
de los sistemas software (lenguajes Smalltalk, Eiffel, C++, Java, Delphi, Phyton,). La
programación orientada a objetos (POO) ha supuesto uno de los avances más importantes de los
últimos años en la ingeniería del software para construir sistemas complejos utilizando el
principio de descomposición, ya que el modelo de objetos subyacente se ajusta mejor a los
problemas del dominio real que la descomposición funcional. La ventaja que tiene es que es fácil
la integración de nuevos datos, aunque también quedan las funciones esparcidas por todo el
código, y tiene los inconvenientes de que, con frecuencia, para realizar la integración de nuevas
funciones hay que modificar varios objetos, y de que se produce un enmarañamiento de los
objetos en funciones de alto nivel que involucran a varias clases.
10
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
función distinta, se tiene que en la primera generación de los sistemas software funciones y datos
se entremezclaban.
En la cuarta generación, sin embargo, esta agrupación se realiza en base a las formas (datos), pero
como se puede observar, en cada conjunto tenemos representadas distintas funcionalidades
(tonalidades), con lo cual éstas también se nos dispersan por todo el sistema.
Uno de los principales inconvenientes con el que nos encontramos al aplicar estas
descomposiciones ya tradicionales es que muchas veces se tienen ejecuciones ineficientes debido
a que las unidades de descomposición no siempre van acompañadas de un buen tratamiento de
aspectos tales como la gestión de memoria, la coordinación, la distribución, las restricciones de
tiempo real, ...
11
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
ni las técnicas funcionales, ni las orientadas a objeto son suficientes para capturar todas las
decisiones de diseño que el programa debe implementar.
Con las descomposiciones tradicionales no se aislan bien estos otros aspectos, sino que quedan
diseminados por todo el sistema enmarañando el código que implementa la funcionalidad básica,
y yendo en contra de la claridad del mismo. Se puede afirmar entonces que las técnicas
tradicionales no soportan bien la separación de competencias para aspectos distintos de la
funcionalidad básica de un sistema, y que esta situación claramente tiene un impacto negativo en
la calidad del software.
La programación orientada a aspectos (POA) es una nueva metodología de programación que aspira
a soportar la separación de competencias para los aspectos antes mencionados. Es decir, que
intenta separar los componentes y los aspectos unos de otros, proporcionando mecanismos que
hagan posible abstraerlos y componerlos para formar todo el sistema. En definitiva, lo que se
persigue es implementar una aplicación de forma eficiente y fácil de entender.
Los lenguajes orientados a objeto se basan en un concepto fundamental llamado objeto y en toda
la tecnología desarrollada en torno a él. Muchos lenguajes se declaran Orientados a Objetos. Pero
la definición exacta del término depende de muchos rasgos y conceptos que se deben cumplir en
su totalidad; estos rasgos y características son:
Para propósito de esta discusión, un lenguaje será considerado Orientado a Objetos Puro si
satisface todos los seis ítems nombrados. Será híbrido si sólo cumple con algunos de esos 6
lineamientos (por lo generar son híbridos cumpliendo los tres primeros).
El estado está compuesto de datos, serán uno o varios atributos a los que se habrán
asignado unos valores concretos (datos).
El comportamiento está definido por los procedimientos o métodos con que puede operar
dicho objeto, es decir, qué operaciones se pueden realizar con él.
12
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La identidad es una propiedad de un objeto que lo diferencia del resto, dicho con otras
palabras, es su identificador (concepto análogo al de identificador de una variable o una
constante).
De esta forma, un objeto contiene toda la información que permite definirlo e identificarlo frente
a otros objetos pertenecientes a otras clases e incluso frente a objetos de una misma clase, al
poder tener valores bien diferenciados en sus atributos. A su vez, los objetos disponen de
mecanismos de interacción llamados métodos que favorecen la comunicación entre ellos. Esta
comunicación favorece a su vez el cambio de estado en los propios objetos. Esta característica
lleva a tratarlos como unidades indivisibles, en las que no se separan ni deben separarse el estado
y el comportamiento.
Ada
C++
C#
Lenguaje de programación D
Object Pascal (Delphi)
Eiffel
Java
JavaScript (la herencia se realiza por medio de la programación basada en prototipos)
Lexico (en castellano)
Objective-C
Ocaml
Oz
Lenguaje de programación R
Perl
PHP (en su versión 5)
Python
Ruby
Smalltalk
13
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Magik (SmallWorld)
VB.NET
Visual FoxPro (en su versión 6)
Visual Basic
XBase++
Muchos de estos lenguajes de programación no son puramente orientados a objetos, sino que son
híbridos que combinan la POO con otros paradigmas
Las Estructuras de Datos Orientadas a Objeto EDOO, pueden ser obtenidas directamente a partir
de los Tipos Abstractos de Datos, con solo añadirles, si es necesario, la funcionalidad, a través de
la implementación de sus operaciones. De este modo los TDA se convierten en clases, por lo
tanto, toda la tecnología y la terminología de la POO se aplica a las estructuras de datos
Orientadas a Objeto.
Los conceptos fundamentales y la terminología a ser utilizados en la definición de las EDOO son
los siguientes:
14
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
adecuado al objeto pertinente. También se puede definir como evento, a la reacción que
puede desencadenar un objeto, es decir la acción que genera.
Mensaje: una comunicación dirigida a un objeto, que le ordena que ejecute uno de sus
métodos con ciertos parámetros asociados al evento que lo generó.
Propiedad o atributo: contenedor de un tipo de datos asociados a un objeto (o a una
clase de objetos), que hace los datos visibles desde fuera del objeto y esto se define como
sus características predeterminadas, y cuyo valor puede ser alterado por la ejecución de
algún método.
Estado interno: es una variable que se declara privada, que puede ser únicamente
accedida y alterada por un método del objeto, y que se utiliza para indicar distintas
situaciones posibles para el objeto (o clase de objetos). No es visible al programador que
maneja una instancia de la clase.
Componentes de un objeto: atributos, identidad, relaciones y métodos.
Representación de un objeto: un objeto se representa por medio de una tabla o entidad
que esté compuesta por sus atributos y funciones correspondientes.
Concepto de Recursividad
Caso Base
Son hechos verdadero que no requieren demostración. En esta parte del algoritmo no existen
llamadas recursivas, son condiciones de terminación de ciclos o llamadas recursivas. Un
algoritmo recursivo puede tener varios casos base.
Caso General
Son hechos que se definen en función al cumplimiento de una definición previa. Estas
definiciones previas las define el mismo algoritmo en llamadas a si mismo con parámetros que
aseguren el cumplimiento de uno de los casos base en cada llamada recursiva.
La recursividad se expresa, generalmente, mediante una función recursiva. Una función que se
llama así misma se denomina recursiva. Podemos usar recursividad si la solución de un problema
está expresada en función de si misma, aunque de menor tamaño y conocemos la solución no-
recursiva para un determinado caso.
15
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Para que una definición recursiva esté completamente identificada es necesario tener un caso base
que no se calcule utilizando casos anteriores y que la división del problema converja a ese caso
base.
1 si n = 0 (caso base)
n
x =
x · xn−1 si n > 0 (caso general)
Otra función recursiva es el factorial. Como se puede ver a continuación la definición recursiva
es clara.
1 si n = 0
n! =
n . (n − 1)! si n > 0
Por ejemplo calculamos el factorial con n=3. Este proceso se muestra paso a paso a continuación:
1) 3! = 3 * 2!
2) 3! = 3 * 2!
2! = 2 * 1!
3) 3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
4) 3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 0!
0! = 1 (caso base)
5) 3! = 3 * 2!
2! = 2 * 1!
1! = 1 * 1
1
6) 3! = 3 * 2!
2! = 2 * 1
1! = 1 * 1 = 1
7) 3! = 3 * 2
2! = 2 * 1 = 2
8) 3! = 3 * 2 = 6
16
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
1. Cálculo de la potencia
1 si n = 0
xn =
x · xn−1 si n > 0
17
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
a si b = 0
suma(a, b) =
1 + suma(a, b − 1) si b > 0
Verdad si V [n] = b
Falso si V [0] 6= b
BusquedaLineal(V, n, b) =
(V [n] == b) ó (b 2 {V [0], . . . , V [n − 1]}) en otro caso
18
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
BusBinRec(v, i, t-1, x)
3. Al modificar los extremos puede darse que i > d, en cuyo caso el proceso termina (Fracaso).
int BusBinRec (int v[], int i, int d, int x) // v arreglo, d tamaño, x valor
{
int centro;
if (i<=d) {
centro = (i+d)/2;
if (v[centro]==x) // Caso base 1
return centro;
else
if (v[centro]>x) // Buscar izda.
return BusBinRec (v,i,centro-1,x);
else // Buscar dcha.
return BusBinRec (v,centro+1,d,x);
}
else // i > d
19
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Una lista es un conjunto lineal de elementos o valores del mismo tipo que se encuentran
ordenados y pueden variar en número.
Los elementos de una lista se almacenan normalmente en forma contigua, es decir un elemento
después de otro, en posiciones consecutivas de memoria. Una lista lineal se almacena en la
memoria principal de una computadora en posiciones contiguas sucesivas de memoria. Esta
asignación de memoria se denomina almacenamiento secuencial o estático.
Las líneas así definidas se llaman contiguas. Las operaciones que se pueden realizar con listas
lineales son las siguientes:
Las operaciones de añadir y eliminar se efectúan únicamente en los extremos de la lista. Esta
limitación es una de las razones por las que esta estructura de datos es poco utilizada como tal;
sin embargo, es útil en casos donde la cantidad de inserciones y/o eliminaciones es reducida, es
decir la estructura es estática. Asimismo, esta estructura permite diseñar otras estructuras más
complejas, implementándolas de manera sencilla; en especial las estructuras dinámicas de pilas y
colas.
3.2. Pilas
Una pila (o snack) es un tipo especial de lista lineal en la que la insrción y el borrado de nuevos
elementos se realiza sólo por un extremo que se denomina cima o tope (top).
20
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La pila es una estructura con numerosas analogías en la vida real: una pila de platos, una pila de
monedas, una pila de cajas de zapatos, una pila de bandeja, un a pila de libros, etc.
Dado que la operación de insertar solo puede hacerse por un extremo, -el superior- los elementos
solo pueden eliminarse en orden inverso al que se insertaron en la pilas. El último elemento que
se pone en la pila es el primero que se puede sacar; por ello, a estas estructuras se les conoce por
el nombre LIFO (Last In, First Out) o UEPS (Ultimo en Entrar, Primero en Salir).
1 2 P-1 P n-1 n
Cima
Cima Longitud máxima de la pila
Otra manera de implementar pilas es de manera dinámica a través de punteros; sin embargo,
cualquiera que sea su implementación, las operaciones sobre las pilas son las mismas y deben ser
transparentes para su utilización
Las operaciones básicas sobre una pila son: poner o meter un nuevo elemento y sacar o quitar un
elemento. En la siguiente lista se muestran estas y otras operaciones y su significado:
Entre las muchas aplicaciones de las pilas están las que se usan en ciencias de la computación
como el rastreo de llamados a subprogramas, el control de bucles, la evaluación de expresiones
aritméticas, etc.
21
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Esta aplicación consiste en calcular el valor de una expresión aritmética dada; es decir, siguiendo las
reglas de la aritmética se debe obtener un valor final. Las expresiones aritméticas, normalmente se
escriben en una notación denominad infija, en la que el operador se encuentra en medio de los operandos.
Una expresión aritmética escrita normalmente en notación infija, se evalúa según los siguientes
pasos:
Se entiende que la notación postfija es aquella cuyos operados aparecen primero, luego aparece el
operador.
Para resolver cada paso es fundamental que los algoritmos utilicen pilas.
Se parte de una expresión en notación infija que tiene operandos, operadores y puede tener
paréntesis. Los operandos vienen representados por letras, los operadores van a ser:
Operadores: ^, *, / , +, -
La transformación se realiza utilizando una pila en la que se almacenan los operadores y los
paréntesis izquierdos. La expresión se va leyendo carácter a carácter, los operandos pasan
directamente a formar parte de la expresión en postfija.
Los operadores se meten en la pila siempre que esta esté vacía, o bien siempre que tengan
mayor prioridad que el operador cima de la pila (o bien igual si es la máxima prioridad). Si la
prioridad es menor o igual se saca el elemento cima de la pila y se vuelve a hacer la
comparación con el nuevo elemento cima.
Los paréntesis izquierdos siempre se meten en la pila, asignándoles la mínima prioridad. Cuando
se lee un paréntesis derecho, hay que sacar todos los operadores de la pila pasando a formar parte
de la expresión postfija, hasta llegar a un paréntesis izquierdo, el cual se elimina de la pila, ya que
los paréntesis no forman parte de la expresión postfija.
El algoritmo termina cuando no hay más ítems en la expresión infija, y la pila esta vacía.
A+B*C/(D–E)-F
22
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
ABC*DE-/+F-
Con el fin de que el algoritmo de conversión de infija a postfija se pueda manejar mejor, es
necesario definir prioridades para los operadores y el paréntesis izquierdo.
Operador Prioridad
^ 3
*, / 2
+, - 1
( 0
23
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Ejercicio.
3.3. Colas
Al igual que las pilas, las colas son estructuras de listas lineales pero con una disciplina diferente
de aquellas. Las colas insertan elemento por un extremo y sacan elementos por el otro. Esto se
conoce como FIFO (First In, First Out) o PEPS (Primero en Entrar, Primero en Salir).
Las eliminaciones se realizan por el comienzo de la lista (front) llamado frente, y las inserciones
se realizan por el otro extremo (rear) o final
En la vida real se tienen numerosos ejemplos de colas: la cola de un cine, la cola de atención en
un banco, una cola de vehículos en una gasolinera, etc. En todas ellas, el primero en llegar es el
primero en ser atendido.
Eliminación Inserción
1 2 n-1 n
Frente Final
Las colas se pueden implementar en forma estática mediante arreglos, como se ve en la figura, o
bien con el uso de punteros, en forma dinámica.
24
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
límite final, en cuyo caso el estado de la cola será aparentemente de cola llena, sin embargo, en el
frente de la cola pueden haber espacios vacíos. Una forma de superar esta limitación es utilizando
el arreglo como un espacio circular que se recicla con el primer elemento, cada vez que la cola
alcanza el final del arreglo. Este problema se puede abordar de diferentes maneras.
La implementación más adecuada para colas es mediante las llamadas listas encadenadas,
mediante el uso de punteros. Esta implementación se estudiará más adelante.
Operaciones Básicas
Implementación de la operaciones
Las operaciones básicas sobre una cola son: poner o meter un nuevo elemento al final y sacar o
quitar un elemento del frente. En la siguiente lista se muestran estas y otras operaciones y su
significado:
Aplicaciones
En estos casos, el primer elemento de la lista realiza su función (pagar comida, pagar entrada para
el partido o para el cine) y deja la cola. Este movimiento está representado en la cola por la
25
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
función pop o desencolar. Cada vez que otro elemento se añade a la lista de espera se añaden al
final de la cola representando la función push o encolar. Hay otras funciones auxiliares para ver
el tamaño de la cola (size), para ver si está vacía en el caso de que no haya nadie esperando
(empty) o para ver el primer elemento de la cola (front).
Las Colas también se utilizan en muchas maneras en los sistemas operativos para planificar el uso
de los distintos recursos de la computadora. Uno de estos recursos es la propia CPU (Unidad
Central de Procesamiento).
Si esta trabajando en una sistema multiusuario, cuando le dice a la computadora que ejecute un
programa concreto, el sistema operativo añade su petición a su “cola de trabajo”.
#ifndef COLA
#define COLA // define la cola
private:
struct Nodo {
T elemento;
Nodo* siguiente; // coloca el nodo en la segunda posicion
}* primero;
Nodo* ultimo;
unsigned int elementos;
public:
Cola() {
elementos = 0;
}
~Cola() {
while (elementos != 0) pop();
}
26
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
void pop() {
Nodo* aux = primero;
primero = primero->siguiente;
delete aux;
--elementos;
}
T consultar() const {
return primero->elemento;
}
};
#endif
Tipos de colas
Colas circulares (anillos): en las que el último elemento y el primero están unidos.
Colas de prioridad: En ellas, los elementos se atienden en el orden indicado por una
prioridad asociada a cada uno. Si varios elementos tienen la misma prioridad, se atenderán
de modo convencional según la posición que ocupen. Hay 2 formas de implementación:
1. Añadir un campo a cada nodo con su prioridad. Resulta conveniente mantener la cola
ordenada por orden de prioridad.
2. Crear tantas colas como prioridades haya, y almacenar cada elemento en su cola.
Bicolas: son colas en donde los nodos se pueden añadir y quitar por ambos extremos; se
les llama DEQUE (Double Ended QUEue). Para representar las bicolas lo podemos hacer
con un array circular con Inicio y Fin que apunten a cada uno de los extremos. Hay
variantes:
Bicolas de entrada restringida: Son aquellas donde la inserción sólo se hace por el final,
aunque podemos eliminar al inicio ó al final.
Bicolas de salida restringida: Son aquellas donde sólo se elimina por el final, aunque se
puede insertar al inicio y al final.
27
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Una cola de atención al público, en realidad es un conjunto de colas que son atendidas en forma
cíclica según determinada prioridad. Esta prioridad puede ser administrada inclusive sobre la
periodicidad de atención a cada cola; es decir las colas con mayor prioridad pueden atenderse en
forma secuencial un cierto número de veces (según el número de elementos que tengan en ese
momento).
Por otra parte, la cantidad de puntos de atención puede ser diseñada según los requerimientos. EL
programa de ser tan flexible que permita configurar todos estos detalles.Esta aplicación tiene
como componente principal la interfaz del usuario.
28
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
4. Almacenamiento dinámico
Una variable es un recurso, entre otros, para manipular un dato binario de modo más legible. Una
variable es un identificador de dato, al igual que el nombre de una función, este NOMBRE
representa para la maquina una localidad de memoria donde el programa puede almacenar y
manipular un dato.
char xx=”B”;
int nn=25;
produce una asociación entre los nombre 'xx', “nn” y sus correspondientes espacios de
almacenamiento en memoria. Por lo tanto hay dos elementos relacionados con el nombre de una
variable: un valor que se puede almacenar allí y una dirección de memoria para la variable.
Existe una correspondencia entre el nombre de cada variable y una dirección de memoria a quien
representa; es decir, el nombre de la variable propiamente dicha (por ejemplo xx) es solo un
“símbolo gráfico” que realmente significa una dirección. Esta asociación podemos representarla
como una tabla virtual de variables. En consecuencia, esta tabla, luego de las anteriores
declaraciones y asignaciones, podría tener el siguiente estado:
xx 0012FF8B
nn 0012FF84
Realmente las direcciones de la tabla virtual existen en lo que podríamos llamar el espacio real
de datos, el cual se puede representar como una tabla que podría tener el siguiente estado:
0012FF8B 00000042 B
0012FF84 00000019 25
29
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Además del identificador "xx", tenemos la palabra "char" que nos indica el tipo (type) de la
variable. El tipo nos indica:
Cuantas celdas de memoria se reservan para ese nombre de variable; es decir cuantos bytes.
Como se interpretarán los bits contenidos en ese espacio o dirección de memoria
Para el manejo de direcciones y contenidos de variables existen dos operadores: & de dirección y
* de indirección.
Operador de direccion &. El operador (ampersand) & aplicado como prefijo a una variable,
devuelve la dirección de memoria en la que se encuentra la variable (sea variable normal o
variable puntero).
Operador de indireccion *. El asterisco escrito como prefijo de una variable puntero o de una
dirección de memoria, permite acceder o referirse al contenido de dicho puntero o dirección de
memoria.
Por ejemplo:
estamos almacenando el carácter „C‟ en la variable xx. Esta última expresión es equivalente a:
xx = ’C’;
Por otra parte se sabe que un byte es la menor unidad de información que pueden direccionar la
mayoría de las computadoras. En la mayoría de las arquitecturas el tipo char ocupa un solo byte.
Un bool admite solo dos valores diferentes, pero es almacenado como un byte. El tipo int de C++
ocupa generalmente 2 bytes, un long 4, double 8, y así con el resto de los tipos.
El otro punto es la relación entre lo que hay en una celda de memoria y como es interpretado. Lo
que hay en un celda cuya extensión es un byte es simplemente un conjunto de ocho estados
posibles (8 bits) que a nivel hardware admiten dos estados diferenciables, estados que pueden ser
simbolizados como 'verdadero/falso', 0/1, o cualquier otro par de valores.
Así, la variable xx del ejemplo anterior en el espacio de datos, tiene como contenido lo siguiente:
30
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
00000042
¿Pero que significa este contenido?, Depende en gran medida del tipo (type) que hayamos
asociado a esa celda (y suponiendo que exista tal asociación). Ese contenido interpretado como
un hexadecimal es 0x42, en decimal es 66, y si fue asociado al tipo char (este es el caso del
ejemplo) representara la letra 'B', cuyo codigo ASCII es igual a 66. En ninguna localidad de
memoria hay algo como la letra 'B', lo que encontramos son valores binarios que en caso de estar
asociados a char y en caso de que lo saquemos en pantalla como char hará que veamos
encendidos ciertos pixeles de pantalla, en los cuales reconoceremos una representación de la letra
'B'.
Puesto que la representación binaria de datos ocupa demasiado espacio, es preferible utilizar el
sistema hexadecimal, que además de ser muy fácil de traducir a binario es más práctico.
Punteros
Luego de las anteriores declaraciones, la tabla virtual de variables podría tener el siguiente
estado:
Nombre de la variable Dirección de memoria
xx 0012FF8B
nn 0012FF84
*x 0012FF80
*n 0012FF7C
31
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
También podemos suponer que el espacio real de datos podría tener el siguiente estado:
0012FF8B 00000042 B
0012FF84 00000019 25
0012FF80 0012FF8B Apunta a xx
0012FF7C 0012FF84 Apunta a nn
Como se puede ver, un puntero es, en esencia, una variable cuyo contenido es una dirección de
memoria, que apunta a un tipo dado.
#include <iostream.h>
#include <stdio.h>
main()
{
char xx='B';
int nn=25;
char *x;
int *n;
x = &xx;
n = &nn;
printf("TABLA DE VARIABLES\n\n");
printf(" Variable Direccion \n\n");
printf("%15s ", "xx"); printf("%15p \n", &xx);
printf("%15s ", "nn"); printf("%15p \n", &nn);
printf("\n\n\nESPACIO DE DATOS\n\n");
printf("%15p ", &x); printf("%15p ", x); printf(" %-15s \n", "apunta a xx");
printf("%15p ", &n); printf("%15p ", n); printf(" %-15s \n", "apunta a nn");
getchar();
}
32
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Independientemente del tamaño (sizeof en C++) del objeto apuntado, el valor almacenado por el
puntero será el de una única dirección de memoria. En sentido estricto un puntero no puede
almacenar la dirección de memoria de un arreglo (completo), sino la de un elemento del arreglo,
y por este motivo no existen diferencias sintácticas entre punteros a elementos individuales y
punteros a arrays. La declaración de un puntero a un tipo char y otro a un arreglo de char es
igual.
Al definir variables o arreglos hemos visto que el tipo (type) modifica la cantidad de bytes que se
usaran para almacenar tales elementos, así un elemento de tipo 'char' utiliza 1 byte, y un entero 2
o 4. No ocurre lo mismo con los punteros, el tipo no influye en la cantidad de bytes asociados al
puntero, pues todas las direcciones de memoria se pueden expresar con solo 2 bytes (o 4 si es una
dirección de otro segmento)
TipoDeDato *NombrePuntero
Ejemplos:
Una estructura de datos muy utilizada en programación es la lista encadena (editores de texto,
compiladote, interfaces de bases de datos, etc.). En C++, es posible crear clases que representen a
listas encadenadas y que facilitarán la gestión de estas listas.
Una lista encadenada consta de nodos que se pueden almacenar en cualquier parte de la memoria
del sistema. Cada nodo contiene los datos asociados con el nodo y la dirección o puntero del
siguiente nodo. La siguiente figura muestra la estructura lógica de la lista encadenada.
33
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Una lista encadenada se puede implementar mediante arreglos, esta manera de implementación
de listas basadas en arreglos funcionan bien para listas estáticas, sin embargo tiene algunas
desventajas importantes:
Alta volatilidad de datos. No resultan eficientes para listas dinámicas en las que
continuamente se están añadiendo y eliminando elementos.
Procesos lentos. La razón es que, en general, para insertar o eliminar un elemento de la lista
tenemos que desplazar otros elementos.
Cantidad limitada de datos. Existen problemas de programación en los cuales no se conocen
con anticipación la cantidad máxima de elementos a insertar a la lista.
Los procesos de inserción eliminación en las listas estáticas requieren recorrer gran parte de
los datos y modificar su posición de todos los elementos causando un retraso en el
procesamiento
La mayoría de estas desventajas pueden ser superadas utilizando listas implementadas con
punteros; es decir manejando dinámicamente la memoria.
Para implementar una lista encadena mediante punteros, es necesario definir el concepto de nodo,
en base al cual se definirá la lista encadenada.
Estructura de Nodo
Dato Null
El Campo de enlace
link proporciona la
dirección o referencia
En caso de que un nodo sea
del siguiente nodo de 34 nodo terminal, se
la lista
representa como Null, cero o
un símbolo de tierra
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
class nodo
{
public:
char dato;
nodo *link;
nodo() {
dato = ' ';
link = NULL;
}
void imprimir();
// void poner(char valor);
// char obtener();
};
Una lista encadenada o lista enlazada es una colección de elementos ó nodos, en donde cada uno
contiene datos y un enlace o link al siguiente nodo de la lista
L
Para acceder a los elementos de la lista encadenada basta conocer la dirección de memoria del
primer nodo.
Dependiendo de donde se aplique la lista enlazada se pueden optar por diversos diseños de
acuerdo a las necesidades del problema en particular a continuación mostraremos algunos de los
diseños mas utilizados
35
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Para agregar un elemento o llegar al último elemento de la lista se tiene que navegar toda la lista
desde el inicio, este hecho se considera como una desventaja ya que representa una tardanza en el
hecho de navegar secuencialmente de nodo a nodo
Primero
Primero Ultimo
L F
class lista {
private :
nodo *L; // apunta al comienzo de la lista
nodo *F; // apunta al final de la lista
int tam;
public:
lista() {
L = NULL;
tam = 0;
}
void tamano();
void anadirFin(char c);
void anadirIni(char c);
void recorrer();
36
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Mejora el diseño anterior manteniendo un campo (tamaño) actualizado en todos los procesos de
inserción y eliminación que permita almacenar la cantidad de nodos de la lista, de modo que el
hecho de conocer la cantidad de nodos no sería más que una simple devolución de esta variable
actualizada en todas las operaciones que modifiquen la cantidad de nodos de la lista.
Primero Ultimo
Tamaño = 3
Definición de operaciones
Las principales operaciones que podemos realizar sobre la lista encadenada simple son:
Recorrido
Inserció n
Borrado
Búsqueda
Operación de Recorrido
Consiste en visitar cada uno de los nodos que forman la lista. Se comienza con el primero, se
toma el valor del campo Link para avanzar al segundo nodo, así sucesivamente.
Cuando se encuentre un link = Null se habrá terminado de recorrer la lista
L F
x
5 2 9 7
0
5 2 9 7
37
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Utilizando una variable auxiliar P que se inicia en L y desde ahí se comienza a navegar de nodo
en nodo utilizando el Link de cada uno de ellos. El hecho de utilizar un puntero auxiliar es para
no alterar el valor del puntero L ya que si se altera se puede perder la dirección de toda la lista
enlazada.
Operación de Inserción
Consiste en insertar un nodo a cualquier parte de la lista, esto se realiza mediante asignación
dinámica de memoria es decir que se reserva memoria para un nuevo nodo y luego se almacena
en él el dato para enlazarlo a la lista en el lugar deseado ya sea al principio de la lista, al final o
entre medio de la lista. En cualquiera de los casos se deben actualizar los punteros de los nodos
adyacentes para mantener la lista enlazada.
El proceso se realiza en cuatro pasos, dada una lista como la que muestra a continuación:
5 2 9 7
L P
5 2 9 7
3) Se copia el campo link del nodo apuntado por P, al campo link del nuevo nodo N:
L P
4
5 2 9 7
38
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
4) Por último, se copia en el campo link del nodo apuntado por P, el puntero N del nuevo nodo:
L P 4
L P
5 2 9 7
5 2 9 7
Operación de Borrado
Consiste en eliminar un nodo de lista enlazada, en este caso se debe actualizar las direcciones de
los punteros necesarios y liberar la memoria ocupada por el nodo al sistema operativo para que
pueda ser utilizado en otras operaciones.
Operación de Búsqueda
Consiste en buscar un elemento cualquiera en la lista enlazada, este hecho se realiza recorriendo
la lista y comparando el dato de cada uno de los nodos visitados con el elemento que se está
buscando hasta que se lo encuentre. Es similar a la operación de recorrido.
Las estructuras de datos dinámicas como son las pilas y las colas son mejor implementadas
mediante el manejo dinámico de memoria, a través de punteros.
Utilizando la estructura nodal de una lista encadena, es posible implementar una pila como una
lista restringida por la disciplina de inserción y eliminación que impone una pila. Esto se puede
realizar utilizando el concepto de herencia de la POO, que permite diseñar una nueva estructura a
partir de una ya existente. En este caso, diseñar una clase pila a partir de la clase lista.
39
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
5. Arboles y Grafos
5.1 Arboles binarios
Un árbol es una estructura no lineal constituida por un conjunto de elementos arreglados en forma
jerárquica, en la que cada elemento tiene un antecesor (padre) y puede tener de cero a dos
sucesores (hijos). Los elementos se denominan nodos.
Existe un único nodo especial llamado raíz que no tiene antecesor.
Antes de seguir entrando en materia, será conveniente dar unas cuantas definiciones:
El primer nodo del árbol recibe el nombre de raíz, los enlaces reciben el nombre de aristas.
Se dice que un nodo B es hijo de un nodo A, si existe alguna arista que va desde A hasta B.
Por ejemplo, en la figura, 7 es hijo de 2, 4 es hijo de 9, 11 es hijo de 6, etc.
Al mismo tiempo se dice que un nodo A es padre de un nodo B si existe una arista que va
desde A hasta B. Ej. 9 es padre de 4, 6 es padre de 5 y de 11, etc.
Se dice que un nodo es hoja, si no tiene hijos. Ej. 11 y 4 son hojas, pero 6, 7, y 9 no lo son.
La rama izquierda de un nodo es el árbol que tiene como raíz el hijo izquierdo de tal nodo,
por ejemplo {7, 2, 6, 5, 11} son los nodos de la rama izquierda de 2.
La rama derecha de un nodo es el árbol que tiene como raíz el hijo derecho de tal nodo.
Los nodos tambien pueden ser llamados vertices.
Nivel: número de ramas que hay que recorrer para llegar de la raíz a un nodo. Ejemplo: el
nivel del nodo 2 es 1 (es un convenio), el nivel del nodo 9 es 3.
Altura: el nivel más alto del árbol. En el ejemplo de la figura la altura es 4.
Amplitud: es el mayor valor del número de nodos que hay en un nivel. En la figura, la
amplitud es 3.
Grado de un nodo: el número de descendientes directos que tiene. Ejemplo: 5 tiene grado 2,
2 tiene grado 0, 6 tiene grado 2.
Grado de un árbol. es el máximo grado de entre todos los nodos.
40
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Definición de árbol
Un árbol es una estructura de datos, que puede definirse de forma recursiva como:
Otra definición nos da el árbol como un tipo de grafo (ver grafos): un árbol es un grafo acíclico,
conexo y no dirigido. Es decir, es un grafo no dirigido en el que existe exactamente un camino
entre todo par de nodos. Esta definición permite implementar un árbol y sus operaciones
empleando las representaciones que se utilizan para los grafos. Sin embargo, en esta sección no
se tratará esta implementación.
Formas de representación
- Mediante un grafo:
Figura 1
a
b
d
c
e
f
En computación se utiliza mucho una estructura de datos llamada árbol binario. Estos árboles
tienen 0, 1 ó 2 descendientes como máximo. El árbol de la figura anterior es un ejemplo válido de
árbol binario.
41
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Se definirá el árbol con una clave de tipo entero (puede ser cualquier otra tipo de datos) y dos
hijos: izquierdo (izq) y derecho (der). Para representar los enlaces con los hijos se utilizan
punteros. El árbol vacío se representará con un puntero nulo.
class Tarbol
{
public:
int clave;
Tarbol *izq;
Tarbol *der;
};
Recorridos en profundidad
* Recorrido en preorden: consiste en visitar el nodo actual (visitar puede ser simplemente
mostrar la clave del nodo por pantalla), y después visitar el subárbol izquierdo y una vez visitado,
visitar el subárbol derecho. Es un proceso recursivo por naturaleza.
Si se hace el recorrido en preorden del árbol de la figura 1 las visitas serían en el orden siguiente:
a,b,d,c,e,f.
* Recorrido en inorden u orden central: se visita el subárbol izquierdo, el nodo actual, y después
se visita el subárbol derecho. En el ejemplo de la figura 1 las visitas serían en este orden:
b,d,a,e,c,f.
42
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La ventaja del recorrido en postorden es que permite borrar el árbol de forma consistente. Es
decir, si visitar se traduce por borrar el nodo actual, al ejecutar este recorrido se borrará el árbol o
subárbol que se pasa como parámetro. La razón para hacer esto es que no se debe borrar un nodo
y después sus subárboles, porque al borrarlo se pueden perder los enlaces, y aunque no se
perdieran se rompe con la regla de manipular una estructura de datos inexistente. Una alternativa
es utilizar una variable auxiliar, pero es innecesario aplicando este recorrido.
Recorrido en amplitud:
Consiste en ir visitando el árbol por niveles. Primero se visitan los nodos de nivel 1 (como mucho
hay uno, la raíz), después los nodos de nivel 2, así hasta que ya no queden más.
Si se hace el recorrido en amplitud del árbol de la figura una visitaría los nodos en este orden:
a,b,c,d,e,f
En este caso el recorrido no se realizará de forma recursiva sino iterativa, utilizando una cola (ver
Colas) como estructura de datos auxiliar. El procedimiento consiste en encolar (si no están
vacíos) los subárboles izquierdo y derecho del nodo extraido de la cola, y seguir desencolando y
encolando hasta que la cola esté vacía.
En la codificación que viene a continuación no se implementan las operaciones sobre colas.
if (a != NULL) {
CrearCola(cola);
encolar(cola, a);
while (!colavacia(cola)) {
desencolar(cola, aux);
visitar(aux);
if (aux->izq != NULL) encolar(cola, aux->izq);
if (aux->der != NULL) encolar(cola, aux->der);
}
}
}
Por último, considérese la sustitución de la cola por una pila en el recorrido en amplitud. ¿Qué
tipo de recorrido se obtiene?
43
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Antes de explicarlo se recomienda al lector que lo intente hacer por su cuenta, es sencillo cuando
uno es capaz de construir el árbol viendo sus recorridos pero sin haber visto el árbol terminado.
Partiendo de los recorridos preorden e inorden del árbol de la figura 1 puede determinarse que la
raíz es el primer elemento del recorrido en preorden. Ese elemento se busca en el array inorden.
Los elementos en el array inorden entre izq y la raíz forman el subárbol izquierdo. Asimismo los
elementos entre der y la raíz forman el subárbol derecho. Por tanto se tiene este árbol:
El subárbol b tiene un subárbol derecho, que no tiene ningún descendiente, tal y como indican los
índices izq y der. Se ha obtenido el subárbol izquierdo completo de la raíz a, puesto que b no
tiene subárbol izquierdo:
44
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Ejercicio
45
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
* Todas las claves del subárbol izquierdo al nodo son menores que la clave del nodo.
* Todas las claves del subárbol derecho al nodo son mayores que la clave del nodo.
* Ambos subárboles son árboles binarios de búsqueda.
Figura 5
Al definir el tipo de datos que representa la clave de un nodo dentro de un árbol binario de
búsqueda es necesario que en dicho tipo se pueda establecer una relación de orden. Por ejemplo,
suponer que el tipo de datos de la clave es un puntero (da igual a lo que apunte). Si se codifica el
árbol en Pascal no se puede establecer una relación de orden para las claves, puesto que Pascal no
admite determinar si un puntero es mayor o menor que otro.
En el ejemplo de la figura 5 las claves son números enteros. Dada la raíz 4, las claves del
subárbol izquierdo son menores que 4, y las claves del subárbol derecho son mayores que 4. Esto
se cumple también para todos los subárboles. Si se hace el recorrido de este árbol en orden
central (inorden) se obtiene una lista de los números ordenada de menor a mayor.
Cuestión: ¿Qué hay que hacer para obtener una lista de los números ordenada de mayor a menor?
Una ventaja fundamental de los árboles de búsqueda es que son en general mucho más rápidos
para localizar un elemento que una lista enlazada. Por tanto, son más rápidos para insertar y
borrar elementos. Si el árbol está perfectamente equilibrado -esto es, la diferencia entre el
número de nodos del subárbol izquierdo y el número de nodos del subárbol derecho es a lo sumo
1, para todos los nodos- entonces el número de comparaciones necesarias para localizar una clave
es aproximadamente de logN en el peor caso. Además, el algoritmo de inserción en un árbol
46
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
binario de búsqueda tiene la ventaja -sobre los arrays ordenados, donde se emplearía búsqueda
dicotómica para localizar un elemento- de que no necesita hacer una reubicación de los elementos
de la estructura para que esta siga ordenada después de la inserción. Dicho algoritmo funciona
avanzando por el árbol escogiendo la rama izquierda o derecha en función de la clave que se
inserta y la clave del nodo actual, hasta encontrar su ubicación; por ejemplo, insertar la clave 7 en
el árbol de la figura 5 requiere avanzar por el árbol hasta llegar a la clave 8, e introducir la nueva
clave en el subárbol izquierdo a 8.
El algoritmo de borrado en árboles es algo más complejo, pero más eficiente que el de borrado en
un array ordenado.
Ahora bien, suponer que se tiene un árbol vacío, que admite claves de tipo entero. Suponer que se
van a ir introduciendo las claves de forma ascendente. Ejemplo: 1, 2, 3, 4, 5, 6.
Se crea un árbol cuya raíz tiene la clave 1. Se inserta la clave 2 en el subárbol derecho de 1. A
continuación se inserta la clave 3 en el subárbol derecho de 2.
Continuando las inserciones se ve que el árbol degenera en una lista secuencial, reduciendo
drásticamente su eficacia para localizar un elemento. De todas formas es poco probable que se de
un caso de este tipo en la práctica. Si las claves a introducir llegan de forma más o menos
aleatoria entonces la implementación de operaciones sobre un árbol binario de búsqueda que
vienen a continuación son, en general, suficientes.
Existen variaciones sobre estos árboles, como los AVL o Red-Black (no se tratan aquí), que sin
llegar a cumplir al 100% el criterio de árbol perfectamente equilibrado, evitan problemas como el
de obtener una lista degenerada.
- Búsqueda
Si el árbol no es de búsqueda, es necesario emplear uno de los recorridos anteriores sobre el árbol
para localizarlo. El resultado es idéntico al de una búsqueda secuencial. Aprovechando las
propiedades del árbol de búsqueda se puede acelerar la localización. Simplemente hay que
descender a lo largo del árbol a izquierda o derecha dependiendo del elemento que se busca.
- Inserción
47
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
- Borrado
La operación de borrado si resulta ser algo más complicada. Se recuerda que el árbol debe seguir
siendo de búsqueda tras el borrado. Pueden darse tres casos, una vez encontrado el nodo a borrar:
1) El nodo no tiene descendientes. Simplemente se borra.
2) El nodo tiene al menos un descendiente por una sola rama. Se borra dicho nodo, y su primer
descendiente se asigna como hijo del padre del nodo borrado. Ejemplo: en el árbol de la figura 5
se borra el nodo cuya clave es -1. El árbol resultante es:
3) El nodo tiene al menos un descendiente por cada rama. Al borrar dicho nodo es necesario
mantener la coherencia de los enlaces, además de seguir manteniendo la estructura como un árbol
binario de búsqueda. La solución consiste en sustituir la información del nodo que se borra por el
de una de las hojas, y borrar a continuación dicha hoja. ¿Puede ser cualquier hoja? No, debe ser la
que contenga una de estas dos claves:
· la mayor de las claves menores al nodo que se borra. Suponer que se quiere borrar el nodo 4
del árbol de la figura 5. Se sustituirá la clave 4 por la clave 2.
· la menor de las claves mayores al nodo que se borra. Suponer que se quiere borrar el nodo 4
del árbol de la figura 5. Se sustituirá la clave 4 por la clave 5.
48
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Codificación: el procedimiento sustituir es el que desciende por el árbol cuando se da el caso del
nodo con descencientes por ambas ramas.
free(aux);
}
}
49
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Ficheros relacionados
Ejercicio resuelto
Escribir una función que devuelva el numero de nodos de un árbol binario. Una solución
recursiva puede ser la siguiente:
Se tiene un fichero de texto ASCII. Para este propósito puede servir cualquier libro electrónico de
la librería Gutenberg o Cervantes, que suelen tener varios cientos de miles de palabras. El
objetivo es clasificar todas las palabras, es decir, determinar que palabras aparecen, y cuantas
veces aparece cada una. Palabras como 'niño'-'niña', 'vengo'-'vienes' etc, se consideran diferentes
por simplificar el problema.
Escribir un programa, que recibiendo como entrada un texto, realice la clasificación descrita
anteriormente.
Ejemplo:
Texto: "a b a c. hola, adios, hola"
Nótese que el empleo de una lista enlazada ordenada no es una buena solución. Si se obtienen
hasta 20.000 palabras diferentes, por decir un número, localizar una palabra cualquiera puede ser,
y en general lo será, muy costoso en tiempo. Se puede hacer una implementación por pura
curiosidad para evaluar el tiempo de ejecución, pero no merece la pena.
50
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La solución pasa por emplear un árbol binario de búsqueda para insertar las claves. El valor de
log(20.000) es aproximadamente de 14. Eso quiere decir que localizar una palabra entre 20.000
llevaría en el peor caso unos 14 accesos. El contraste con el empleo de una lista es simplemente
abismal. Por supuesto, como se ha comentado anteriormente el árbol no va a estar perfectamente
equilibrado, pero nadie escribe novelas manteniendo el orden lexicográfico (como un
diccionario) entre las palabras, asi que no se obtendrá nunca un árbol muy degenerado. Lo que
está claro es que cualquier evolución del árbol siempre será mejor que el empleo de una lista.
Por último, una vez realizada la lectura de los datos, sólo queda hacer un recorrido en orden
central del árbol y se obtendrá la solución pedida en cuestión de segundos.
Ejercicios propuestos
In- Orden (30, 60, 210, 240, 250, 255, 280, 285)
Pre- Orden (60, 30, 210, 280, 250, 240, 255, 285)
Reconstruir el árbol binario.
2. Del árbol reconstruido anteriormente graficar como queda el árbol después de eliminar el
240, el 210, y el 60
In- Orden (30, 60, 210, 240, 250, 255, 280, 285)
Pre- Orden (60, 30, 210, 280, 250, 240, 255, 285)
Reconstruir el árbol binario.
3. Realizar un método para eliminar todos los nodos hojas existentes en un árbol binario.
4. Realizar un método para eliminar todos los nodos incompletos existentes en un árbol
binario.
51
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
8. Realizar un método para el ADT árbol que permita obtener el elemento mayor de los
menores de un elemento dado es decir el menor más próximo a un elemento x.
9. Realizar un método para eliminar un elemento cualquiera del árbol utilizando en vez del
nodo sucesor in-orden el menor más próximo.
10. Implementar un método para eliminar todos los elementos menores a un elemento x
52
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
5.3. Árboles B
Como una propuesta inicial para la ordenación lógica de datos se presenta la estructura de datos
Arbol Binario de Búsqueda (ABB). El cual mediante el uso de punteros permite establecer un
orden de relación entre los datos sin importar su orden físico.
Recordemos que en un ABB cada nodo contiene un dato, así como punteros a los subarboles
izquierdo y derecho. El primer nodo se denomina raíz del árbol y aquellos nodos que están al
final de las ramas se llaman hojas.
Para buscar un dato en el ABB se debía recorrer el árbol desde su raíz y comparar el dato buscado
con el dato existente en el nodo. Si era menor al dato en el nodo se buscaba en el subarbol
izquierdo y si era mayor en el subarbol derecho. Así recursivamente, hasta encontrarlo o
encontrarse con una rama vacía.
Estos árboles binarios tan simples, aunque fáciles de entender y de implementar, tienen algunas
desventajas en la práctica. Si los datos no están bien distribuidos o son añadidos de forma no
aleatoria, el árbol puede resultar bastante asimétrico, dando lugar a un aumento bastante amplio
en el tiempo total de recorrido.
Como solución ha este problema se presentó la estructura de datos Arbol Binario Balanceado
(AVL), el cual tenía las mismas propiedades que un ABB pero además debía satisfacer que las
alturas de los subarboles izquierdo y derecho no difirieran en más de uno. Esto se logra utilizando
herramientas de balanceo que se denominan rotaciones.
Ahora retomando nuestra idea inicial de tener una gran cantidad de datos almacenada en algún
dispositivo secundario (HDD, Diskette, CD, etc.). Los ABB y los AVL deben realizar un acceso
al disco cada vez que cargan en memoria un dato del fichero. Lo cual es bastante costoso si
consideramos que el tiempo de búsqueda en una cantidad N de datos es del orden de log 2N más el
tiempo de cada acceso al disco (Un acceso al diskette, por ejemplo, demora alrededor de 1 seg.)
Para optimizar esta situación usaremos la estructura de datos Arbol B y sus métodos de
mantenimiento. El Método de Trabajo de los Arboles B sobre los datos en memoria secundaria es
abordado en el apartado Funcionamiento de un Arbol B.
53
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Veamos un ejemplo real. Si como Ingenieros en Computación se nos encarga administrar la Base
de Datos de todos los sufragantes de Chile (los cuales son cientos de miles), entonces deberíamos
usar una Estructura de Datos adecuada a nuestra problemática. Sabiendo que se nos pide Buscar
personas, Verificar domicilios, Inscribir un sufragante, Eliminar a un sufragante, etc. La manera
más idónea de hacerlo es usar una estructura dinámica y capaz de almacenar grandes cantidades
de datos. Es por eso que elegimos los Arboles B, porque nos entregan una eficaz administración
de los datos de muchas personas.
Otro ejemplo real y concreto, es el uso en los Sistemas Operativos con Administración de
Memoria del Tipo Virtual.
Los Arboles B son muy funcionales en todos estos tipos de problemas en los cuales se requiere
una cantidad de accesos mínimos al dispositivo secundario, para poder procesar mucha
información.
Funcionamiento
El Arbol B es un TDA de búsqueda equilibrado, diseñado para ser usado con grandes conjuntos
de datos en almacenamiento secundario.
Generalmente se considera a los Arboles B como el mejor método para implementar al TDA
dinámico en una unidad de disco.
A diferencia de los Arboles Binarios (que sólo podían almacenar un dato en cada nodo,
induciéndo así a realizar un acceso al disco cada vez que se carga un dato en el árbol antes de ser
procesado), el Arbol B accede al disco mediante bloques de datos, es decir, agrupa los datos en
paquetes para su lectura o escritura de así serlo.
Esta propuesta reduce bastante el número de accesos al dispositivo secundario, optimizando así el
rendimiento de nuestro sistema informático.
54
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Así por ejemplo, supongamos que tenemos un archivo con nueve mil registros de empleados
(RUT, nombre, apellido, dirección, cargo) de 100 Bytes cada registro, como se muestra en la
Figura 1. Además sabemos que el bloque del disco es de 512 Bytes y que cada puntero al bloque
de disco es de 2 Bytes.
Si hubiésemos usado un ABB para administrar los datos en este archivo, tendríamos que haber
accesido al disco unas 9000 veces para cargar el árbol completo en memoria principal (lo cual es
bastante lento).
Ahora si usamos un Arbol B con 5 registros (500 Bytes) y 6 punteros (12 Bytes) por cada nodo,
tendremos que acceder al disco unas 1800 veces. Ya que empaquetados los datos en bloques de 5
registros por nodo. Esto es mucho más rápido y eficiente que en el caso de los ABB.
Por lo tanto, ya debemos tener clara la idea que el Arbol B es el TDA óptimo para administrar
una gran cantidad de datos en memoria secundaria. Ahora que sabemos el uso de los Arboles B y
su forma de trabajar, les mostraremos su definición formal.
55
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
¿Qué es un Arbol B?
A fines de los años sesenta, R. Bayer y E. McCreight postularon un criterio muy razonable de
organizar datos en un fichero externo, lo llamaron Arbol B.
La Figura 2 muestra un Arbol B de orden 2 con 3 niveles. Todas las páginas tienen 2, 3 o 4
elementos; la excepción es la raíz que puede contener un solo elemento únicamente. Todas las
páginas de hoja aparecen en el nivel 3.
Búsqueda
Suponiendo que hemos cargado en memoria primaria una página P del Arbol B, entonces
podemos aplicar los métodos ordinarios de búsqueda entre las llaves k1 .... km .
Nota: Si m es muy grande, se puede hacer una búsqueda del tipo "Dividir para reinar". Pero si
es pequeña, bastará con realizar una búsqueda Secuencial.
56
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
1. ki-1 < x < ki+1 para 1 <= i < m. Proseguimos la búsqueda en la página p i
2. km < x La búsqueda prosigue en la página pm
3. x < k1 La búsqueda prosigue en la página p0
Si en algún caso el apuntador desigando es NULL, esto es, si no hay página de hijo, entonces
tampoco existe un elemento con la llave x en el Arbol B y la búsqueda finaliza.
Inserción
Para analizar esta situación, considérese la Figura 4(a) que muestra un Arbol B de orden 2.
Puesto que cada página en un Arbol B de orden n (excepto la raíz ) contiene entre n y 2n
elementos, cada página del ejemplo tiene entre 2 y 4 elementos. En cada página debe existir un
indicador (que no está reflejado en la figura) para informar sobre el número de elementos que
tiene la página. Primero se procede a Buscar desde la raíz hasta localizar la página apropiada para
la inserción. Entonces se realiza la inserción. Refiriéndonos a la Figura 4(a), uno puede ver que
cuando se inserta el elemento 24, la Búsqueda termina sin éxito en la segunda hoja. Puesto que la
hoja puede alojar otro elemento, se inserta el elemento nuevo simplemente, dando lugar al Arbol
que se muestra en la Figura 4(b).
Figura 4. (a) Un Arbol B de orden 2, y (b) el mismo árbol tras la inserción del elemento 24
La otra situación que se presenta y la más problemática, es cuando se inserta un elemento en una
página ya llena. Esto puede afectar la Estructura del Arbol y ocasionar asignación de páginas
nuevas.
Para comprender lo que sucede en este caso, analizemos la Figura 5 que ilustra la inserción de la
llave 22 en un Arbol B de orden 2. La acción se realiza en los siguientes pasos:
1. Se descubre que falta la llave 22; la inserción en la página C es imposible porque C ya está llena.
2. La página C se divide en dos páginas (esto es, se asigna una nueva página D).
3. Las 2n + 1 llaves se distribuyen uniformemente en C y D, y la llave de la mitad se sube un nivel hacia la
página madre A.
57
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Este plan tan elegante preserva todas las Propiedades típicas de los Arboles B. En particular, las
páginas divididas contienen exactamente n elementos. Desde luego, la inserción de un elemento
en la página madre puede hacer que ésta se desborde, con lo cual ocasiona que la división se
propague. En el caso extremo, puede propagarse hasta la raíz. Es decir, la única manera en que el
Arbol B pueda aumentar su altura. Tiene pues una manera singular de crecer: crece de las hojas
hacia la raíz.
Borrado
En cualquier caso, después de la eliminación, debe seguir una comprobación del número de
elementos restantes en la página, pues si m < n se tiene se estaría violando las Propiedades para el
Arbol B de orden n y entonces, se requiere reorganizar el Arbol.
Para analizar el caso 1 (el más sencillo), considérse el Arbol B de orden 2 que se muestra en la
Figura 6(a).
Ahora bien, supongámos que deseamos eliminar del Arbol el elemento con valor 14. El primer
procedimiento es Buscar dicho elemento y determinar su posición en el Arbol (se encuentra en
una página hoja). Una vez encontrado, procedemos a eliminarlo del Arbol y mover los elementos
adyacentes a sus nuevas posiciones. Finalmente se debe realizar una verificación. Si la página en
58
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
donde fué eliminado dicho elemento cumple con las Propiedades de Arbol B de orden 2, entonces
se queda como está. En caso contrario, se debería realizar una combinación de páginas. En
nuestro caso sólo debemos eliminarlo y volver a ordenar los elmentos de la página. El Arbol que
se obtiene después del borrado del elemento con valor 14 se muestra en la Figura 6(b).
Figura 6. (b) El mismo Arbol B de la Figura 6(a) tras el borrado del elemento 14
59
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La reorganización se da tomando un elemeto del padre, quien, a su vez debe tomar una elemento
del hermano. Pero puede ocurrir que ya el hermano haya alcanzado su tamaño mínimo n, y no
tenga, por tanto, posibilidad de prestar un elemento; entonces las dos páginas hermanas se unen
en una sola, conteniendo las 2n - 1 elementos de las dos hermanas más un elemeto central
proveniente del padre. La combinación de páginas, causadas por cantidades de elementos en las
páginas, menores a las permitidas, puede prolongarse a los niveles superiores, y en el caso
extremo hasta la raíz, que cuando queda reducida a un tamaño nulo se borra, produciéndose
reducción de la altura del árbol.
Costos
Costo de Buscar
lognN
accesos al dispositivo secundario. De este modo, el costo de procesar una operación de Búsqueda
crece de forma logarítmica en relación con el tamaño del archivo.
El peor caso de Búsqueda corresponde cuando se está buscando un elemento que está en la hoja
del Arbol y además está situado al final de la página hoja.
Pero como el "Tiempo de acceso a memoria secundaria" es una constante (muchas veces bastante
significativa), podemos obviarla si usamos el criterio asintótico. Y decir que el costo de Inserción
y Borrado en un Arbol B de orden n que contiene las claves de un archivo externo de N
elementos es a lo más de:
lognN
60
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
La Tabla 1 muestra cómo puede ser de razonable el costo logarítmico, incluso para archivos de
gran tamaño. Por ejemplo, en un Arbol B de orden 50 que contenga las claves que indexan a un
fichero de un millón de registros, se puede realizar una operación de Búsqueda, Inserción o
Borrado con 4 accesos como mucho.
Casos especiales
Búsqueda
Caso peor
Esta situación se presenta cuando el elemento que se está buscando se encuentra al final de una
página hoja del Arbol B.
Caso mejor
El mejor caso es claramente evidente, y se presenta cuando el elemento buscado es el primer dato
de la raíz del Arbol.
Inserción
Caso peor
Ocurre cuando se inserta un elemento una página hoja que ya está completa. Y además su página
padre también está completa. Esto conlleva, irremediablemente, a que el Arbol aumente su altura.
Caso mejor
Esta situación se presenta cuando se está insertando un elemento en la raíz del Arbol, que aún no
está completa.
Borrado
Caso peor
Esta situación se presenta cuando el elemento que se desea borrar se encuentra al final de una
página hoja con 2n elementos.
61
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Caso mejor
El mejor caso es cuando el elemento borrado es el primer dato de la raíz del Arbol. que además
tiene un solo dato.
Conclusión
Que existe una inmensa gama de sistemas de información computacional, en los cuales se debe
administrar eficientemente grandes volúmenes de datos en archivos externos. Por ejemplo, en el
caso de las Bases de Datos, se deben realizar las operaciones de Actualización, Búsqueda,
Borrado e Incorporación de nuevos datos de la forma más eficiente que se pueda. Este ejemplo de
las BDs a su vez comprende una serie de subtemas, como por ejemplo la Administración de
Memoria, Los Diccionarios, etc. Todos ellos requieren la utilización de Tipos de Datos
Abstractos adecuados. Es decir, que permitan la manipulación eficiente de un gran cantidad de
información. Bajo ésta problemática es que nacen o se fueron creados, los Arboles B. (Ver Cómo
nacieron el Arbol B)
Los Arboles B constituyen la Estructura de Datos óptima para administrar grandes cantidades de
datos en ficheros externos. Gracias a su Estructura, el tiempo de Buscar, Insertar y Borrar datos
es mínimo.
Otra ventaja de los Arboles B es que dichas operaciones de mantenimiento son de fácil
entendimiento lógico. Sin embargo, al momento de ser implementadas comienzan a surgir
bastantes detalles, a veces son engorrosos (Ver Simulación)
Otra característica a tomar en cuenta cuando se trabaja con los Arboles B es: la versatilidad que
éstos tienen. (Véase Tipos de Arboles B)
Los Costos de Buscar, Insertar y Borrar son el punto fuerte de los Arboles B. La mayoría de los
Arboles Binarios requieren en promedio unos logN accesos al dispositivo de almacenamiento de
datos, para realizar operaciones de Búsqueda, Inserción y Borrado. Donde N es el número de
datos. En cambio los Arboles B, solamente necesitan log nN accesos. (Véase Costos). Donde n
es la cantidad máxima de datos que caben en una página (Véase Introducción). Esto reduce
significativamente el número de accesos, ya que si incrementamos n, entonces log nN decrece.
Tal vez, el único defecto que tiene el Arbol B que nosotros estudiamos es que a veces sus páginas
están solamente utilizadas al 50% de su capacidad. Lo que puede ser un desperdicio de memoria
considerable si se tiene una cantidad de datos demasiado grande.
62
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
TRABAJOS PRACTICOS
Trabajo práctico Nº 1
1. Identifique los Tipos Abstractos de Datos que hubiera utilizado o desarrollado en los semestres anteriores
2. Diseñar un T.A.D. para representar y manejar números quebrados
3. Crear un T.A.D que represente un tipo de dato Conjunto y todas sus operaciones Unión, Intersección, Diferencia
simétrica, etc.
4. Diseñar los T.A.D. necesarios para modelar el problema de una agenda en la cual cada registro de la agenda
puede tener n e-mails, identificar las siguientes operaciones
a) Adición de registros de personas.
b) Eliminación de registros
c) Búsqueda de registros
d) Listado de personas ordenadas por nombres.
e) Listado de personas ordenados por e-mail.
1.- Realizar un algoritmo recursivo para verificar si un número tiene al menos un dígito cero.
2.- Realizar un algoritmo recursivo para contar cuantos dígitos tiene un número
3.- Realizar un algoritmo recursivo para fusionar dos números enteros positivos en un tercer número.
4.- Realizar un algoritmo recursivo para inicializar una lista con N elementos 0 y 1 intercalados. Ejemplo si N = 5, la
lista debe contener [0,1,0,1,0,1]
7.- Realizar un algoritmo recursivo para obtener la suma de los elementos impares de una lista.
8.- Realizar un algoritmo recursivo para obtener la suma de los elementos de una sub-lista definida por las
posiciones (j,k) desde la posición j hasta k.
9.- Realizar un algoritmo recursivo para invertir los elementos de una lista doblemente enlazada
10.- Realizar un algoritmo recursivo fusionar dos listas en una tercera lista ejemplo L1 =(2,3,5) L2 = (5,4,7,2,3) L3 =
L1+ L2 = (2,3,5,5,4,7,2,3)
Trabajo práctico Nº 2
1. Realizar un programa que resuelva un ecuación de segundo grado con una incógnita utilizando solo
punteros (No debe utilizar variables que no sean punteros)
63
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
2. Realizar un programa para resolver un sistema de ecuaciones de 3 incógnitas con tres variables utilizando
solo punteros.
3. Realizar un programa para obtener el mayor elemento de N números introducidos por el usuario utilizando
solo punteros.
4. Realizar un programa para calcular cuántos dígitos impares tiene un numero entero positivo utilizando solo
punteros.
5. Realizar un modulo en c++ que permita almacenar números aleatorios a un StringGrid pasado como
parámetro en todo caso utilizar solo punteros.
6. Realizar un algoritmo obtener los resultados de la serie de fibonaci en un ListBox pasado como parámetro.
7. Realizar un programa que permita crear un edit en tiempo de ejecución utilizando solo punteros.
8. Realizar un programa que permita almacenar en un vector N números enteros, Debe asignarse memoria
dinámicamente según la cantidad exacta que el usuario necesita almacenar en el vector.
9. Para las estructuras de datos Listas estáticas realizar un procedimiento para buscar el número más repetido
del vector (Utilizar solo punteros) y el acceso a los elementos del vector no realizar de la forma V[i], buscar otra
alternativa considerando que V es un puntero.
10. Realizar un procedimiento para invertir una cadena utilizando punteros a char.
Trabajo práctico Nº 3
1. Escribir un procedimiento que añada un nuevo elemento en la lista enlazada a partir del elemento i-ésimo.
2. Escribir un procedimiento que elimine un elemento de la lista enlazada, indicado por un parámetro
(Posición).
3. Dada un lista enlazada de números enteros, escribir las rutinas necesarias,
para que la liste este ordenada en orden creciente la ordenación se debe hacer de al menos 3 métodos de
ordenación.
4. Se quiere representar un tipo abstracto de datos conjunto de tal forma que los elementos estén almacenados en
la lista enlazada, escribir una unidad para implementar el TAD conjunto mediante listas enlazadas.
5. Realizar un método para la clase Tconjunto que permita realizar la UNIÓN INTERSECCIÓN Y DIFERENCIA DE
CONJUNTOS sobre la estructura de datos.
6. Implementar un método para obtener el conjunto potencia de un conjunto.
7. Implementar un método para realizar la diferencia simétrica de dos conjuntos.
8. Implementar el método para encontrar el complemento de un conjunto.
9. Realizar una estructura para representar un juego de bingo sobre listas enlazadas.
10. Realizar un método que permite generar y almacenar N cartones para un bingo.
Expresión postfija
_____________________________
b) 2 + (6 – 10)/( 5 – 6) ^ 3.
64
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
Expresión postfija
_____________________________
c) 6-5/(6 – 10*5/6) ^ 3.
Expresión postfija
_____________________________
Expresión postfija
_____________________________
Expresión postfija
_____________________________
2.- Definir el ADT para implementar una aplicación que permita evaluar expresiones aritméticas introducidas por el
usuario en formato cadena.
3.- Definir un ADT para implementar una aplicación que permita graficar cualquier función en el plano de
coordenadas X,Y la función debe ser introducida por el usuario.
4.- Implementar el método para evaluar la expresión en formato cadena de la notación infija a la notación postfija
utilizando listas.
5.- Implementar el método para evaluar la expresión en formato postfija de de la lista en función a una valor par a la
variable X de la función f(x)
65
Apuntes de Estructuras de datos SASCI Rodolfo Arana Gonzales
BIBLIOGRAFÍA
66